PUT call on parameter-defined JSON - bash

I have a script that goes like this where "get_customers" is my pre-defined function and I have to pass each of the following four values as parameter to PUT call for all the customers. However, I am getting the error HTTP 400 Bad Request)","error":"ERROR_BAD_REQUEST" when running this. Anyone knows how I can pass JSON body using this for-loop in PUT call? Is my script wrong?
name=($(get_customers | jq --raw-output '.values[].name'))
tenantId=($(get_customers | jq --raw-output '.values[].tenantId'))
nodeId=($(get_customers | jq --raw-output '.values[].nodeId'))
d=($(get_customers | jq --raw-output '.values[].id'))
for (( i=0; i<${#name[#]}; i++ )); do
curl -X PUT --header "Content-Type: application/json" --header "Accept: application/json" --header "Authorization: Bearer ${API_TOKEN}" -d '{"id":"${d[i]}","name":"${name[i]}","tenantId":"${tenantId[i]}","nodeId":"${nodeId[i]}"}' -k "${URL}/api/file/files/${d[i]}"
done

You are using single quotes, where variables are not expanded. Try this:
for (( i=0; i<${#name[#]}; i++ )); do
curl -X PUT --header "Content-Type: application/json"\
--header "Accept: application/json"\
--header "Authorization: Bearer ${API_TOKEN}"\
-d "$(cat << EOF
{"id":"${d[i]}","name":"${name[i]}","tenantId":"${tenantId[i]}","nodeId":"${nodeId[i]}"}
EOF
)" -k "${URL}/api/file/files/${d[i]}"
done

Related

use parameter in curl command

I have a parameter which is container and i want to use this parameter during run curl command. I use like below but it gives an error. Any idea about that? I use it in bash script.
curl -X 'GET' 'https://mycontainer/api/v2.0/projects/testproject/repositories/$(container)/artifacts?page=1&page_size=1&with_tag=true&with_label=false&with_scan_overview=false&with_signature=false&with_immutable_status=false&with_accessory=false' -H 'accept: application/json' -H 'X-Accept-Vulnerabilities: application/vnd.security.vulnerability.report; version=1.1, application/vnd.scanner.adapter.vuln.report.harbor+json; version=1.0' -H 'authorization: Basic YWhtZXQuY2Fua2F5YUBucy5ubDo2MkVEbDIxUEM=' | jq '.[].tags[].name' > output2.txt
use " instead of '.
and for the variable substitution use ${}.
The command would be:
curl -X 'GET' "https://mycontainer/api/v2.0/projects/testproject/repositories/${container}/artifacts?page=1&page_size=1&with_tag=true&with_label=false&with_scan_overview=false&with_signature=false&with_immutable_status=false&with_accessory=false" -H 'accept: application/json' -H 'X-Accept-Vulnerabilities: application/vnd.security.vulnerability.report; version=1.1, application/vnd.scanner.adapter.vuln.report.harbor+json; version=1.0' -H 'authorization: Basic YWhtZXQuY2Fua2F5YUBucy5ubDo2MkVEbDIxUEM=' | jq '.[].tags[].name' > output2.txt

how to put 2 elements from jq variables in one request?

There is a part of the script where each request receives a response and is written to a variable. How to do it in one request with writing to variables?
boolStatus=$(curl -X 'GET' \
"https://tsit-app1/api/v2/workItems/$case?versionNumber=0" \
-H 'accept: application/json' \
-H "Authorization: $apiKey" | jq '.isAutomated')
echo $boolStatus
name=$(curl -X 'GET' \
"https://tsit-app1/api/v2/workItems/$case?versionNumber=0" \
-H 'accept: application/json' \
-H "Authorization: $apiKey" | jq '.name')
echo $name
I tried
curl -X 'GET' \
"https://tsit-app1/api/v2/workItems/$case?versionNumber=0" \
-H 'accept: application/json' \
-H "Authorization: $apiKey" | jq '"boolStatus=\(.isAutomated)", "name=\(.name)"'
but in echo i get
"boolStatus=true",
"name=bla bla"
need to
echo $boolStatus
true
echo $name
bla bla
One way would be to use the #sh string interpolation and then use your shell's eval.
Using the string interpolation would output something like:
boolStatus=true
name='abc'
which can then be fed to eval:
vars="$(curl ... | jq -r '#sh "boolStatus=\(.isAutomated)", #sh "name=\(.name)"')"
eval "$vars"
or explicitly output the line break:
jq -r '#sh "boolStatus=\(.isAutomated)\nname=\(.name)"'
Disclaimer: Note that this will evaluate any shell code and might open your system to malicious code (#sh escapes the values, but it's always a good idea to be aware of this).
Use process substitution to allow two uses of read to read from the output of jq.
{ read boolStatus; read name; } < <(curl ... | jq -r '.isAutomated, .name')
(assuming the name does not contain any newlines).
At the very least, you can save the output to process with jq twice.
response=$(curl ...)
name=$(echo "$response" | jq -r .name)
boolStatus=$(echo "$response" | jq -r .isAutomated)

Doing PUT using bash script

I am writing a bash script that does this :
Get a list of customers
For each customer, query an API (get files) This returns id and name
For each file, do a PUT.
My question is, I want to both "id" and "name" in my PUT body, so how can I get this in a single loop on "files" API. I have written this:
URL="https://some-url.com"
API_TOKEN="some-token"
get_customers() {
curl --insecure \
--fail \
--header "Accept: application/json" \
--header "Authorization: Bearer ${API_TOKEN}" \
-k ${URL}/api/org/customers
}
get_files() {
curl --insecure \
--fail \
--header "Accept: application/json" \
--header "Authorization: Bearer ${API_TOKEN}" \
-k ${URL}/api/files/files
}
put_capability() {
echo ""
curl --insecure \
--fail \
--silent \
--header "Content-Type: application/json" \
--header "Authorization: Bearer ${API_TOKEN}" \
--data #- \
${URL}/api/files/files/{id}
echo ""
}
customers=($(get_customers | jq --raw-output '.values[].id'))
for customer_id in "${customers[#]}"; do
fileshares=($(get_files ${customer_id} | jq --raw-output '.values[].id'))
fileshares-names=($(get_files ${customer_id} | jq --raw-output '.values[].name'))
for fileshare_id in "${fileshares[#]}"; do
#call function put_capability and do subsequent PUT.
#PUT needs two parameters, fileshares and fileshares-names
done
done
Basically, I don't want to call "get_files" twice as I am doing now. I need both the "fileshares" and "fileshares-names" in my subsequent PUT API. Can this be done in one for loop on file shares?
You can parse get_files output once by storing it in a temp file like that :
customers=($(get_customers | jq --raw-output '.values[].id'))
for customer_id in "${customers[#]}"; do
get_files ${customer_id} > /tmp/cust.txt
fileshares=($(cat /tmp/cust.txt | jq --raw-output '.values[].id'))
fileshares-names=($(cat /tmp/cust.txt | jq --raw-output '.values[].name'))
for fileshare_id in "${fileshares[#]}"; do
#call function put_capability and do subsequent PUT.
#PUT needs two parameters, fileshares and fileshares-names
done
done

passing values with spaces in curl command using POST

I am trying to pass values with spaces in curl POST method. I am directing the values through a txt file. POST command does not allow me to pass values with spaces using the for while loop, But when i pass it without while loop it accepts the value without any error.
Below are the commands
This works perfectly fine
curl -d '{"name": "equity calculation support", "email": "email#test.com"}' -H "Authorization: Basic YWRtaW46YWRtaW4=" -H "Content-Type: application/json" -H "Accept: application/json" -X POST http://localhost:3000/api/teams
{"message":"Team created","teamId":103}
when using while loop and IFS it doesn't take the values with spaces:
while IFS= read -r line ; do curl -d '{"name": "'$line'"}' -H "Authorization: Basic YWRtaW46YWRtaW4=" -H "Content-Type: application/json" -H "Accept: application/json" -X POST 'http://localhost:3000/api/teams'; done < /tmp/group.txt
group.txt file contains the values .
You aren't quoting the expansion of $line:
while IFS= read -r line ; do
curl -d '{"name": "'"$line"'"}' \
-H "Authorization: Basic YWRtaW46YWRtaW4=" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-X POST 'http://localhost:3000/api/teams'
done < /tmp/group.txt
However, it's a better idea to let a tool like jq produce the JSON, to ensure that any characters in $line that need to be escaped to produce proper JSON do, indeed, get escaped.
while IFS= read -r line; do
d=$(jq -n --argjson x "$line" '{name: $x}')
curl -d "$d" ...
done < /tmp/group.txt
It looks like the JSON you want to create would fit on a single line, so you could also process all of /tmp/group.txt with a single call to jq, and pipe its output to your loop.
jq -c -R '{name: .}' | while IFS= read -r line; do
curl -d "$line" ...
done

Bash unable to read variable [duplicate]

This question already has answers here:
Difference between single and double quotes in Bash
(7 answers)
Closed 4 years ago.
I am curling Azure Log Analytics for some info, but first I need to grab an OAuth token from 1 command and pass it into the next. I have the following Curl commands which I have tested fine on their own (copying pasting the output for the next input), however I want to pass the OAuth token output as a variable for an automation task, but for some reason it is not able to read the variable into the next command.
token=$(curl -X POST \
https://login.microsoftonline.com/{{subscriptionID}}/oauth2/token \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=client_credentials&client_id={{clientID}}&client_secret={{clientSECRET}}&resource=https%3A%2F%2Fapi.loganalytics.io' \
| jq .access_token)
curl -X POST \
https://api.loganalytics.io/v1/workspaces/{{workspaceID}}/query \
-H 'Authorization: Bearer $token' \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/json' \
-d '{ "query": "AzureActivity | summarize count() by Category" }'
Unfortunately when I run this command it responds back that a token is needed.
{"error":{"message":"Valid authentication was not provided","code":"AuthorizationRequiredError"}}
However, if I were to echo the $token variable it shows that it was saved
beefcake#ubuntu:~$ echo $token
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1...."
As I said, the commands work fine if I remove the token=$(..) and just copy/paste the output into the next input. Any ideas why this won't work for automation?
#Aserre had the right mindset. Turns out that jq copies the inverted commas " " from the string, whereas the bearer token requires none. Thus my first command should have looked like this:
token=$(curl -X POST \
https://login.microsoftonline.com/{{subscriptionID}}/oauth2/token \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=client_credentials&client_id={{clientID}}&client_secret={{clientSECRET}}&resource=https%3A%2F%2Fapi.loganalytics.io' \
| jq -r .access_token)
Note the last line that has the -r command for removing the double quotes. Which showed an echo of:
beefcake#ubuntu:~$ echo $token
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIs....
Note the " " removed from the echo. In addition to that, I had to alter the next command where I replaced 'Authorization: Bearer $token' with "Authorization: Bearer $token":
curl -X POST \
https://api.loganalytics.io/v1/workspaces/{{workspaceID}}/query \
-H "Authorization: Bearer $token" \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/json' \
-d '{ "query": "AzureActivity | summarize count() by Category" }'

Resources