Terraform's external data source: STDOUT syntax unclear - json

I would like to use terraform's external data source to identify certain AWS EC2 instances:
data "external" "monitoring_instances" {
program = ["bash", "${path.module}/../bash/tf_datasource_monitoring.sh"]
query = {
env = var.env_stage
}
}
The bash script is using AWS CLI to return a list of instance IDs.
But I keep receiving this Error: command "bash" produced invalid JSON: json: cannot unmarshal array into Go value of type string
I don't understand what the expected syntax of my script's STDOUT would be for terraform to understand the result.
So let's assume the script is supposed to return 3 instance IDs i-1, i-2 and i-3.
What would be the correct JSON syntax to be returned to terraform?
Examples, that do NOT work:
{
"instances": [
"i-1",
"i-2",
"i-3"
]
}
[
"i-1",
"i-2",
"i-3"
]

It is a known issue in Terraform for provider-external: https://github.com/hashicorp/terraform-provider-external/issues/2. It was opened a while ago, unfortunately is still present for latest version (Terraform v1.011).
You may want to avoid returning JSON objects which contain arrays.

I had the same issue, while executing a python script to generate a dynamic bigquery schema, which is per definition an array of JSONs.
I solved it, by implementing a wrapper JSON with the schema as a string value (see dummy code below).
# get_dynamic_bigquery_schema.py
import json
bigquery_schema = [
{"name": "int_field", "type": "INTEGER", "mode": "NULLABLE", "description": "int_field"},
{"name": "int_field_repeated", "type": "INTEGER", "mode": "REPEATED", "description": "int_field_repeated"}
]
wrapper_json = {'actual_output': str(json.dumps(bigquery_schema))}
print(json.dumps(wrapper_json))
which I can then access within terraform
# main.tf
data "external" "bigquery_schema" {
program = ["python", "${path.module}/get_dynamic_bigquery_schema.py"]
}
locals {
bigquery_schema= data.external.bigquery_schema.result['actual_output']
}

Related

Invalid key/value pair when adding json to vault

I tried: vault kv put -format=json secrets/path #file.json
Getting this error:
Failed to parse K=V data: invalid key/value pair "#file.json": json cannot unmarshal array into Go value of type map[string] interface {}
When trying vault kv put -format=json secrets/path file.json I get:
Failed to parse K=V data: invalid key/value pair "file.json": format must be key=value
Not sure what I'm doing wrong.
The first form is more correct if you're attempting to pass a JSON file as an argument. The second form is not referencing a file, it's just invalid syntax.
The error message on the first form suggests that the JSON file you have is formatted incorrectly. The required format will depend on your KV engine version. If you are working with a KV v2 engine, it is required to put your key:value pairs into a data top level map. If you are working with a KV v1 engine, each key:value pair needs to itself be a top level object.
KV v1:
{
"key": "value",
"foo": "bar",
"bar": "baz"
}
KV v2:
{
"data": {
"key": "value",
"foo": "bar",
"bar": "baz"
},
"options": {}
}
The -output-curl-string flag is great for inspecting what the vault CLI tool is doing under the hood, try adding it and see what transformations the binary applies to your commands.

AWS CLI events put-targets EcsParameters (structure)

I am trying to get the current Task Definition of an ECS Cluster then update the revision in the cloud bridge event target.
This is what I have so far:
james#LAPTOP:/mnt/c/Users/james$ target_id="xxx_hourly_cron"
james#LAPTOP:/mnt/c/Users/james$ aws events list-targets-by-rule --rule `echo $target_id` > rule-target.json
james#LAPTOP:/mnt/c/Users/james$ cat rule-target.json
{
"Targets": [
{
"Id": "xxx_hourly_cron",
"Arn": "arn:aws:ecs:eu-west-2:000000000000:cluster/xxx-cluster",
"RoleArn": "arn:aws:iam::000000000000:role/ecsEventsRole",
"EcsParameters": {
"TaskDefinitionArn": "arn:aws:ecs:eu-west-2:000000000000:task-definition/xxx-cron:55",
"TaskCount": 1,
"EnableECSManagedTags": false,
"EnableExecuteCommand": false,
"PropagateTags": "TASK_DEFINITION"
}
}
]
}
james#LAPTOP:/mnt/c/Users/james$ aws events put-targets --rule `echo $target_id` --targets --EcsParameters jsonfile?
The last command is where I am struggling:
within the AWS docs I am not to sure what it means by structure I have tried json and I have tried to escape it.
Here is the docs I am looking at:
https://docs.aws.amazon.com/cli/latest/reference/events/put-targets.html
With AWS CLI commands, you can often replace the majority of the arguments supplied to a command with a single JSON file using the --cli-input-json argument. This can make it far easier to work with complex structures as input arguments to CLI commands.
In the above example, you would modify the rule-target.json output to become an input (rule-target-input.json) for the next using something like the following:
{
"Rule": "xxx_hourly_cron",
"Targets": [
{
"Id": "xxx_hourly_cron",
"Arn": "arn:aws:ecs:eu-west-2:000000000000:cluster/xxx-cluster",
"RoleArn": "arn:aws:iam::000000000000:role/ecsEventsRole",
"EcsParameters": {
"TaskDefinitionArn": "arn:aws:ecs:eu-west-2:000000000000:task-definition/xxx-cron:55",
"TaskCount": 1,
"EnableECSManagedTags": false,
"EnableExecuteCommand": false,
"PropagateTags": "TASK_DEFINITION"
}
}
]
}
And then feeding that into the input using something like the following:
aws put-targets --cli-input-json file://rule-target-input.json

Invalid JSON while submitting spark submit job via NiFi

I am trying to submit a spark job where I am setting a date argument in conf property and I am running it through a script in NiFi. However, when I am running the script I am facing an error.
Spark Submit Code in the script:
aws emr add-steps --cluster-id "$1" --steps '[{"Args":["spark-submit","--deploy-mode","cluster","--jars","s3://tvsc-lumiq-edl/jars/ojdbc7.jar","--executor-memory","10g","--driver-memory","10g","--conf","spark.hadoop.yarn.timeline-service.enabled=false","--conf","currDate='\"$5\"'","--class",'\"$2\"','\"$3\"','\"$4\"'],"Type":"CUSTOM_JAR","ActionOnFailure":"CONTINUE","Jar":"command-runner.jar","Properties":"","Name":"Spark application"}]' --region "$6"
and after I run it, I get the below error:
ExecuteStreamCommand[id=5b08df5a-1f24-3958-30ca-2e27a6c4becf] Transferring flow file StandardFlowFileRecord[uuid=00f844ee-dbea-42a3-aba3-0edcabfc50a2,claim=StandardContentClaim [resourceClaim=StandardResourceClaim[id=1607082757752-507103, container=default, section=223], offset=29, length=-1],offset=0,name=6414901712887990,size=0] to nonzero status. Executable command /bin/bash ended in an error:
Error parsing parameter '--steps': Invalid JSON:
[{"Args":["spark-submit","--deploy-mode","cluster","--jars","s3://tvsc-lumiq-edl/jars/ojdbc7.jar","--executor-memory","10g","--driver-memory","10g","--conf","spark.hadoop.yarn.timeline-service.enabled=false","--conf","currDate="Fri
Where am I going wrong?
You can use JSONLint to validate your JSON, which makes it easier to see why its wrong.
In your case, you are wrapping the final 3 values in single quotes ' rather than double quotes "
Your steps JSON should look like:
[{
"Args": [
"spark-submit",
"--deploy-mode",
"cluster",
"--jars",
"s3://tvsc-lumiq-edl/jars/ojdbc7.jar",
"--executor-memory",
"10g",
"--driver-memory",
"10g",
"--conf",
"spark.hadoop.yarn.timeline-service.enabled=false",
"--conf",
"currDate='\"$5\"'",
"--class",
"\"$2\"",
"\"$3\"",
"\"$4\""
],
"Type": "CUSTOM_JAR",
"ActionOnFailure": "CONTINUE",
"Jar": "command-runner.jar",
"Properties": "",
"Name": "Spark application"
}]
Specifically, these 3 lines:
"\"$2\"",
"\"$3\"",
"\"$4\""
Instead of the original:
'\"$2\"',
'\"$3\"',
'\"$4\"'

Pass bash variable (string) as jq argument to walk JSON object

This is seemingly a very basic question. I am new to JSON, so I am prepared for the incoming facepalm.
I have the following JSON file (test-app-1.json):
"application.name": "test-app-1",
"environments": {
"development": [
"server1"
],
"stage": [
"server2",
"server3"
],
"production": [
"server4",
"server5"
]
}
The intent is to use this as a configuration file and reference for input validation.
I am using bash 3.2 and will be using jq 1.4 (not the latest) to read the JSON.
The problem:
I need to return all values in the specified JSON array based on an argument.
Example: (how the documentation and other resources show that it should work)
APPLICATION_ENVIRONMENT="developement"
jq --arg appenv "$APPLICATION_ENVIRONMENT" '.environments."$env[]"' test-app-1.json
If executed, this returns null. This should return server1.
Obviously, if I specify text explicitly matching the JSON arrays under environment, it works just fine:
jq 'environments.development[]' test-app-1.json returns: server1.
Limitations: I am stuck to jq 1.4 for this project. I have tried the same actions in 1.5 on a different machine with the same null results.
What am I doing wrong here?
jq documentation: https://stedolan.github.io/jq/manual/
You have three issues - two typos and one jq filter usage issue:
set APPLICATION_ENVIRONMENT to development instead of developement
use variable name consistently: if you define appenv, use $appenv, not $env
address with .environments[$appenv]
When fixed, looks like this:
$ APPLICATION_ENVIRONMENT="development"
$ jq --arg appenv "$APPLICATION_ENVIRONMENT" '.environments[$appenv][]' test-app-1.json
"server1"

Need help! - Unable to load JSON using COPY command

Need your expertise here!
I am trying to load a JSON file (generated by JSON dumps) into redshift using copy command which is in the following format,
[
{
"cookieId": "cb2278",
"environment": "STAGE",
"errorMessages": [
"70460"
]
}
,
{
"cookieId": "cb2271",
"environment": "STG",
"errorMessages": [
"70460"
]
}
]
We ran into the error - "Invalid JSONPath format: Member is not an object."
when I tried to get rid of square braces - [] and remove the "," comma separator between JSON dicts then it loads perfectly fine.
{
"cookieId": "cb2278",
"environment": "STAGE",
"errorMessages": [
"70460"
]
}
{
"cookieId": "cb2271",
"environment": "STG",
"errorMessages": [
"70460"
]
}
But in reality most JSON files from API s have this formatting.
I could do string replace or reg ex to get rid of , and [] but I am wondering if there is a better way to load into redshift seamlessly with out modifying the file.
One way to convert a JSON array into a stream of the array's elements is to pipe the former into jq '.[]'. The output is sent to stdout.
If the JSON array is in a file named input.json, then the following command will produce a stream of the array's elements on stdout:
$ jq ".[]" input.json
If you want the output in jsonlines format, then use the -c switch (i.e. jq -c ......).
For more on jq, see https://stedolan.github.io/jq