0

I am looking for advice on how to parse a file and select certain fields. The selected fields then need to be included in an API push to a separate system using curl.

The challenge is that the amount of fields needed may vary each time the file is populated. I can however use the keys "key" and the values provided after that in "value".

So in the following example I'm wanting to capture these values (though a separate message may have more or less):

{
    "result": {
        "problems": [{
            "id": "8103182743126107297_1579010239089V2",
            "startTime": 1579010239089,
            "endTime": -1,
            "displayName": "297",
            "impactLevel": "INFRASTRUCTURE",
            "status": "OPEN",
            "severityLevel": "AVAILABILITY",
            "commentCount": 0,
            "tagsOfAffectedEntities": [{
                "context": "CONTEXTLESS",
                "key": "JBOSS"
            }, {
                "context": "CONTEXTLESS",
                "key": "AC"
            }, {
                "context": "CONTEXTLESS",
                "key": "Host Name",
                "value": "servernameX.com"
            }, {
                "context": "CONTEXTLESS",
                "key": "Tomcat"
            }],
            "rankedImpacts": [{
                "entityId": "PROCESS_GROUP_INSTANCE-2XXXE58A78A142D7",
                "entityName": "service Tomcat *",
                "severityLevel": "AVAILABILITY",
                "impactLevel": "INFRASTRUCTURE",
                "eventType": "PROCESS_UNAVAILABLE"
            }, {
                "entityId": "PROCESS_GROUP_INSTANCE-A2F65660B538D9CF",
                "entityName": "JBoss EAP",
                "severityLevel": "AVAILABILITY",
                "impactLevel": "INFRASTRUCTURE",
                "eventType": "PROCESS_UNAVAILABLE"
            }],
            "affectedCounts": {
                "INFRASTRUCTURE": 2,
                "SERVICE": 0,
                "APPLICATION": 0,
                "ENVIRONMENT": 0
            },
            "recoveredCounts": {
                "INFRASTRUCTURE": 0,
                "SERVICE": 0,
                "APPLICATION": 0,
                "ENVIRONMENT": 0
            },
            "hasRootCause": true
        }],
        "monitored": {
            "INFRASTRUCTURE": 235,
            "SERVICE": 19,
            "APPLICATION": 1,
            "ENVIRONMENT": 1
        }
    }
}

Then... once those values are captured, convert them into a new JSON string like this (only the value of "Host" will change):

{
    "State": "OPEN",
    "ProblemID": "55555",
    "ImpactedEntity": "Alert from Maintenance Window",
    "ProblemTitle": "Process unavailable",
    "Host": "captured value 1(JBOSS), captured value 2(AC), captured value 3(HostName), captured value 4(servernameX.com),captured value 5(Tomcat), "
}

I need to fit them into an curl POST and have it execute.

curl -v -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '(the JSON above)' 'http://serverA.com/?apiKey=8675309:p'

This is a Linux box and I have python 2.7 available on it

So to summarize:

  • We need to parse a flat file for the values of interest (call it file.x The amount of values may vary but there is always a key word/s to identify)

  • We need to take those values of interest and place them in a CURL
    statement that does an API push (The format is listed above)

How can this be accomplished? Ultimately I will be scheduling this in a cron task for different times. Please advise and thank you so kindly all !

runatyr
  • 57
  • 9
  • 1
    I believe you'd benefit from using the `jq` package which will help you parse and search for values. While not a complete answer, please consider it as a lead. More info at https://stedolan.github.io/jq/manual/ – Adhoc Jan 15 '20 at 17:05
  • I have tried to reformat your question as to both be more readable *and* contain syntactically valid JSON (making parts of source code bold does not work on this website, but having actual working code people can copy easily outweighs that). Please check that I did not get the details wrong. – Tomalak Jan 15 '20 at 17:34
  • There's a lot of logic implied by your sample inputs and outputs that isn't fleshed out in the question (f/e, needing a lookup table that can map `PROCESS_UNAVAILABLE` to `Process unavailable`; knowing how to pick which "ranked impact" to report when there's more than one; etc). – Charles Duffy Jan 15 '20 at 17:35
  • ...implicitly requiring an answer to intuit and address those details generally goes outside the scope of what can be considered a reasonable Stack Overflow question; can you try to narrow it down to content that (1) you don't know how to do, which (2) isn't already covered by existing Q&A entries (like [Parsing JSON with UNIX tools](https://stackoverflow.com/questions/1955505/parsing-json-with-unix-tools))? – Charles Duffy Jan 15 '20 at 17:38
  • Thank you for the edit on format – runatyr Jan 15 '20 at 17:44
  • Your sample is not fully consistent because there is `"key": "Tomcat"` and I don't see a reason why it would be the only one that doen't appear in the output. – Tomalak Jan 15 '20 at 17:50
  • Thank you Tomalek, this was an error of omission. I have added it – runatyr Jan 15 '20 at 18:19
  • @runatyr if you're open to install `jtc` utility (I'm the developer), then I can provide you with the exact solution to your query – Dmitry Jan 15 '20 at 23:45

1 Answers1

1

If jq is available, would you try the following:

i=1
while IFS=$'\n' read -r x; do
    str+=$(printf "captured value %d(%s), " "$i" "$x")
    ((i++))
done < <(jq -r '.. | .key? // empty, .value? // empty' < file.json)

cat <<EOS
{
    "State": "OPEN",
    "ProblemID": "55555",
    "ImpactedEntity": "Alert from Maintenance Window",
    "ProblemTitle": "Process unavailable",
    "Host": "$str"
}
EOS

Output:

{
    "State": "OPEN",
    "ProblemID": "55555",
    "ImpactedEntity": "Alert from Maintenance Window",
    "ProblemTitle": "Process unavailable",
    "Host": "captured value 1(JBOSS), captured value 2(AC), captured value 3(Host Name), captured value 4(servernameX.com), captured value 5(Tomcat), "
}

If you want to assign a variable json to the output above, modify the cat statement as:

json=$(cat <<EOS
{
    "State": "OPEN",
    "ProblemID": "55555",
    "ImpactedEntity": "Alert from Maintenance Window",
    "ProblemTitle": "Process unavailable",
    "Host": "$str"
}
EOS
)

Then you can embed the variable json in the curl command line.

[Explanations]

  • The filter .. for the jq command traverses the json tree recursively and get all the values keyed by .key or .value. The null values are removed with // empty.
  • The output of the jq command is fed to the while loop and the formatted values are appended to the string str one by one.
tshiono
  • 21,248
  • 2
  • 14
  • 22
  • Thank you for your answer! getting jq on the system will not be an issue other than scheduling it for a production system :) I'll run this through test again but this is really clean and almost self explanatory, even for a person who does not get to do python as much as they would like. As an FYI, this is being leveraged for a monitoring system that currently has some limitations. Just wanted to say thank you again :) – runatyr Jan 16 '20 at 12:16
  • @runatyr Thanks for the feedback. It's my pleasure to know it's working well. Good luck! – tshiono Jan 16 '20 at 12:24