Using the Barracuda REST API with Ansible - token authentication doesn't work - rest

I'm trying to use the REST API by Barracuda ADC and/or WAF and, while it works when I use cURL (from the documentation):
Request:
$ curl
-X POST \
-H "Content-Type:application/json" \
-d '{"username": "admin", "password": "admin"}' \ http://10.11.19.104:8000/restapi/v2/login
Response:
{"token":"eyJldCI6IjEzODAyMzE3NTciLCJwYXNzd29yZCI6ImY3NzY2ZTFmNTgwMzgyNmE1YTAzZWZlMzcy\nYzgzOTMyIiwidXNlciI6ImFkbWluIn0=\n"}
Then we should use that token to execute commands on the API, something like:
$ curl
-X GET \
-H "Content-Type:application/json" \
-u 'eyJldCI6IjEzODAyMzE3NTciLCJwYXNzd29yZCI6ImY3NzY2ZTFmNTgwMzgyNmE1YTAzZWZlMzcy\nYzgzOTMyIiwidXNlciI6ImFkbWluIn0=\n': \
http://10.11.19.104:8000/restapi/v2/virtual_service_groups
And it'll give me a response listing (in this case) my virtual service groups, and it works with cURL.
Now, when I try to use ansible to do the same things, the first step to authenticate goes successfully (I can even use the generated token with cURL and it accepts it), but the second step to run the commands with the generated token always gives me 401 error (Invalid credentials):
- name: login into the load balancer
uri:
url: "{{ barracuda_url }}/login"
method: POST
body_format: json
body:
username: "{{ barracuda_user }}"
password: "{{ barracuda_pass }}"
headers:
Content-Type: application/json
return_content: yes
force_basic_auth: yes
register: login
tags: login, debug
- debug: msg="{{ login.json.token }}"
tags: debug
- name: get
uri:
url: "{{ barracuda_url }}/virtual_service_groups"
method: GET
body_format: json
user: "{{ login.json.token }}:"
headers:
Content-Type: application/json
return_content: yes
force_basic_auth: yes
register: response
Output of my playbook:
TASK [loadbalancer : login into the load balancer] *****************************
ok: [localhost]
TASK [loadbalancer : debug] ****************************************************
ok: [localhost] => {
"msg": "eyJldCI9IjE0ODQ2MDcxNTAiXCJwYXNzd29yZCI6IjRmM2TlYWMwN2ExNmUxYWFhNGEwNTU5NTMw\nZGQ3ZmM3IiwiaXNlciI6IndpYSJ9\n"
}
TASK [loadbalancer : get] ******************************************************
fatal: [localhost]: FAILED! => {"changed": false, "connection": "close", "content": "{\"error\":{\"msg\":\"Please log in to get valid token\",\"status\":401,\"type\":\"Invalid Credentials\"}}", "content_type": "application/json; charset=utf8", "date": "Mon, 16 Jan 2017 22:32:30 GMT", "failed": true, "json": {"error": {"msg": "Please log in to get valid token", "status": 401, "type": "Invalid Credentials"}}, "msg": "Status code was not [200]: HTTP Error 401: ", "redirected": false, "server": "BarracudaHTTP 4.0", "status": 401, "transfer_encoding": "chunked", "url": "http://10.11.19.104:8000/restapi/v2/virtual_service_groups"}

Remove the colon from "{{ login.json.token }}:" in user argument. Use:
user: "{{ login.json.token }}"
The colon is not a part of a username, but a curl syntax (used in your example to avoid an interactive password prompt):
-u, --user <user:password>
[ ]
If you simply specify the user name, curl will prompt for a password.

Related

Get run id after triggering a github workflow dispatch event

I am triggering a workflow run via github's rest api. But github doesn't send any data in the response body (204).
How do i get the run id of the trigger request made?
I know about the getRunsList api, which would return runs for a workflow id, then i can get the latest run, but this can cause issues when two requests are submitted at almost the same time.
This is not currently possible to get the run_id associated to the dispatch API call in the dispatch response itself, but there is a way to find this out if you can edit your worflow file a little.
You need to dispatch the workflow with an input like this:
curl "https://api.github.com/repos/$OWNER/$REPO/actions/workflows/$WORKFLOW/dispatches" -s \
-H "Authorization: Token $TOKEN" \
-d '{
"ref":"master",
"inputs":{
"id":"12345678"
}
}'
Also edit your workflow yaml file with an optionnal input (named id here). Also, place it as the first job, a job which has a single step with the same name as the input id value (this is how we will get the id back using the API!):
name: ID Example
on:
workflow_dispatch:
inputs:
id:
description: 'run identifier'
required: false
jobs:
id:
name: Workflow ID Provider
runs-on: ubuntu-latest
steps:
- name: ${{github.event.inputs.id}}
run: echo run identifier ${{ inputs.id }}
The trick here is to use name: ${{github.event.inputs.id}}
https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#inputs
Then the flow is the following:
run the dispatch API call along with the input named id in this case with a random value
POST https://api.github.com/repos/$OWNER/$REPO/actions/workflows/$WORKFLOW/dispatches
in a loop get the runs that have been created since now minus 5 minutes (the delta is to avoid any issue with timings):
GET https://api.github.com/repos/$OWNER/$REPO/actions/runs?created=>$run_date_filter
example
in the run API response, you will get a jobs_url that you will call:
GET https://api.github.com/repos/$OWNER/$REPO/actions/runs/[RUN_ID]/jobs
the job API call above returns the list of jobs, as you have declared the id jobs as 1st job it will be in first position. It also gives you the steps with the name of the steps. Something like this:
{
"id": 3840520726,
"run_id": 1321007088,
"run_url": "https://api.github.com/repos/$OWNER/$REPO/actions/runs/1321007088",
"run_attempt": 1,
"node_id": "CR_kwDOEi1ZxM7k6bIW",
"head_sha": "4687a9bb5090b0aadddb69cc335b7d9e80a1601d",
"url": "https://api.github.com/repos/$OWNER/$REPO/actions/jobs/3840520726",
"html_url": "https://github.com/$OWNER/$REPO/runs/3840520726",
"status": "completed",
"conclusion": "success",
"started_at": "2021-10-08T15:54:40Z",
"completed_at": "2021-10-08T15:54:43Z",
"name": "Hello world",
"steps": [
{
"name": "Set up job",
"status": "completed",
"conclusion": "success",
"number": 1,
"started_at": "2021-10-08T17:54:40.000+02:00",
"completed_at": "2021-10-08T17:54:42.000+02:00"
},
{
"name": "12345678", <=============== HERE
"status": "completed",
"conclusion": "success",
"number": 2,
"started_at": "2021-10-08T17:54:42.000+02:00",
"completed_at": "2021-10-08T17:54:43.000+02:00"
},
{
"name": "Complete job",
"status": "completed",
"conclusion": "success",
"number": 3,
"started_at": "2021-10-08T17:54:43.000+02:00",
"completed_at": "2021-10-08T17:54:43.000+02:00"
}
],
"check_run_url": "https://api.github.com/repos/$OWNER/$REPO/check-runs/3840520726",
"labels": [
"ubuntu-latest"
],
"runner_id": 1,
"runner_name": "Hosted Agent",
"runner_group_id": 2,
"runner_group_name": "GitHub Actions"
}
The name of the id step is returning your input value, so you can safely confirm that it is this run that was triggered by your dispatch call
Here is an implementation of this flow in python, it will return the workflow run id:
import random
import string
import datetime
import requests
import time
# edit the following variables
owner = "YOUR_ORG"
repo = "YOUR_REPO"
workflow = "dispatch.yaml"
token = "YOUR_TOKEN"
authHeader = { "Authorization": f"Token {token}" }
# generate a random id
run_identifier = ''.join(random.choices(string.ascii_uppercase + string.digits, k=15))
# filter runs that were created after this date minus 5 minutes
delta_time = datetime.timedelta(minutes=5)
run_date_filter = (datetime.datetime.utcnow()-delta_time).strftime("%Y-%m-%dT%H:%M")
r = requests.post(f"https://api.github.com/repos/{owner}/{repo}/actions/workflows/{workflow}/dispatches",
headers= authHeader,
json= {
"ref":"master",
"inputs":{
"id": run_identifier
}
})
print(f"dispatch workflow status: {r.status_code} | workflow identifier: {run_identifier}")
workflow_id = ""
while workflow_id == "":
r = requests.get(f"https://api.github.com/repos/{owner}/{repo}/actions/runs?created=%3E{run_date_filter}",
headers = authHeader)
runs = r.json()["workflow_runs"]
if len(runs) > 0:
for workflow in runs:
jobs_url = workflow["jobs_url"]
print(f"get jobs_url {jobs_url}")
r = requests.get(jobs_url, headers= authHeader)
jobs = r.json()["jobs"]
if len(jobs) > 0:
# we only take the first job, edit this if you need multiple jobs
job = jobs[0]
steps = job["steps"]
if len(steps) >= 2:
second_step = steps[1] # if you have position the run_identifier step at 1st position
if second_step["name"] == run_identifier:
workflow_id = job["run_id"]
else:
print("waiting for steps to be executed...")
time.sleep(3)
else:
print("waiting for jobs to popup...")
time.sleep(3)
else:
print("waiting for workflows to popup...")
time.sleep(3)
print(f"workflow_id: {workflow_id}")
gist link
Sample output
$ python3 github_action_dispatch_runid.py
dispatch workflow status: 204 | workflow identifier: Z7YPF6DD1YP2PTM
get jobs_url https://api.github.com/repos/OWNER/REPO/actions/runs/1321463229/jobs
get jobs_url https://api.github.com/repos/OWNER/REPO/actions/runs/1321463229/jobs
get jobs_url https://api.github.com/repos/OWNER/REPO/actions/runs/1321463229/jobs
get jobs_url https://api.github.com/repos/OWNER/REPO/actions/runs/1321475221/jobs
waiting for steps to be executed...
get jobs_url https://api.github.com/repos/OWNER/REPO/actions/runs/1321463229/jobs
get jobs_url https://api.github.com/repos/OWNER/REPO/actions/runs/1321475221/jobs
waiting for steps to be executed...
get jobs_url https://api.github.com/repos/OWNER/REPO/actions/runs/1321463229/jobs
get jobs_url https://api.github.com/repos/OWNER/REPO/actions/runs/1321475221/jobs
waiting for steps to be executed...
get jobs_url https://api.github.com/repos/OWNER/REPO/actions/runs/1321463229/jobs
get jobs_url https://api.github.com/repos/OWNER/REPO/actions/runs/1321475221/jobs
get jobs_url https://api.github.com/repos/OWNER/REPO/actions/runs/1321463229/jobs
workflow_id: 1321475221
It would have been easier if there was a way to retrieve the workflow inputs via API but there is no way to do this at this moment
Note that in the worflow file, I use ${{github.event.inputs.id}} because ${{inputs.id}} doesn't work. It seems inputs is not being evaluated when we use it as the step name
Get WORKFLOWID
gh workflow list --repo <repo-name>
Trigger workflow of type workflow_dispatch
gh workflow run $WORKFLOWID --repo <repo-name>
It doesnot return the run-id which is required get the status of execution
Get latest run-id WORKFLOW_RUNID
gh run list -w $WORKFLOWID --repo <repo> -L 1 --json databaseId | jq '.[]| .databaseId'
Get workflow run details
gh run view --repo <repo> $WORKFLOW_RUNID
This is workaround that we do. It is not perfect, but should work.
inspired by the comment above, made a /bin/bash script which gets your $run_id
name: ID Example
on:
workflow_dispatch:
inputs:
id:
description: 'run identifier'
required: false
jobs:
id:
name: Workflow ID Provider
runs-on: ubuntu-latest
steps:
- name: ${{github.event.inputs.id}}
run: echo run identifier ${{ inputs.id }}
workflow_id= generates a random 8 digit number
now, later, date_filter= use for time filter, now - 5 minutes \
generates a random ID
POST job and trigger workflow
GET action/runs descending and gets first .workflow_run[].id
keeps looping until script matches random ID from step 1
echo run_id
TOKEN="" \
GH_USER="" \
REPO="" \
REF=""
WORKFLOW_ID=$(tr -dc '0-9' </dev/urandom | head -c 8) \
NOW=$(date +"%Y-%m-%dT%H:%M") \
LATER=$(date -d "-5 minutes" +"%Y-%m-%dT%H:%M") \
DATE_FILTER=$(echo "$NOW-$LATER") \
JSON=$(cat <<-EOF
{"ref":"$REF","inputs":{"id":"$WORKFLOW_ID"}}
EOF
) && \
curl -s \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $TOKEN" \
"https://api.github.com/repos/$GH_USER/$REPO/actions/workflows/main.yml/dispatches" \
-d $JSON && \
INFO="null" \
COUNT=1 \
ATTEMPTS=10 && \
until [[ $CHECK -eq $WORKFLOW_ID ]] || [[ $COUNT -eq $ATTEMPTS ]];do
echo -e "$(( COUNT++ ))..."
INFO=$(curl -s \
-X GET \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $TOKEN" \
"https://api.github.com/repos/$GH_USER/$REPO/actions/runs?created:<$DATE_FILTER" | jq -r '.workflow_runs[].id' | grep -m1 "")
CHECK=$(curl -s \
-X GET \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $TOKEN" \
"https://api.github.com/repos/$GH_USER/$REPO/actions/runs/$INFO/jobs" | jq -r '.jobs[].steps[].name' | grep -o '[[:digit:]]*')
sleep 5s
done
echo "Your run_id is $CHECK"
output:
1...
2...
3...
Your run_id is 67530050
I recommend using the convictional/trigger-workflow-and-wait action:
- name: Example
uses: convictional/trigger-workflow-and-wait#v1.6.5
with:
owner: my-org
repo: other-repo
workflow_file_name: other-workflow.yaml
github_token: ${{ secrets.GH_TOKEN }}
client_payload: '{"key1": "value1", "key2": "value2"}'
This takes care of waiting for the other job and returning a success or failure according to whether the other workflow succeeded or failed. It does so in a robust way that handles multiple runs being triggered at almost the same time.
the whole idea is to know which run was dispatched, when id was suggested to use on dispatch, this id is expected to be found in the response of the GET call to this url "actions/runs" so now user is able to identify the proper run to monitor. The injected id is not part of the response, so extracting another url to find your id is not helpful since this is the point where id needed to identify the run for monitoring

How to refer environment variable inside GitHub workflow?

I'm trying to read the the GitHub environment variable inside the request json payload while making the curl request but somewhat these variables are not resolving and it gives an error the values I'm trying to read are KEY_VAULT and ACR_PATH:SNAPSHOT_VERSION inside the flow create container web. I've attached the GitHub workflow sample below.
name: Pull Request
on:
pull_request:
types: [review_requested]
env:
KEY_VAULT: "some vault"
SNAPSHOT_VERSION: ${{ format('{0}-SNAPSHOT', github.event.number) }}
GITHUB_ISSUE_NUMBER: ${{ github.event.number }}
GITHUB_REPO: ${{ github.event.repository.name }}
DEPLOYMENT_NOTIFICATION_URL_TOKEN: ${{ secrets.SOME_TOKEN }}
DEPLOYMENT_URL_TOKEN: 123
ENVIRONMENT: sandbox
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
with:
fetch-depth: 0
- name: Docker login
#if: steps.pr-label.outputs.result == 'true'
uses: azure/docker-login#v1
with:
login-server: acr-login.com
username: user
password: pwd
- name: Publish Snapshot To ACR
#if: steps.pr-label.outputs.result == 'true'
run: |
echo steps.pr-label.outputs.result
echo Publishing to $ACR_PATH:$SNAPSHOT_VERSION
docker build . -t $ACR_PATH:$SNAPSHOT_VERSION
docker push $ACR_PATH:$SNAPSHOT_VERSION
- name: Create Container Web
#if: steps.pr-label.outputs.result == 'true'
run: |
AUTH_HEADER="Authorization: token $DEPLOYMENT_URL_TOKEN"
CONTAINER_WEB_NAME="CONATINER"
PROJECT_NAME="tirumalesh-automate"
REGION="US"
URL="https://abcd.com/$REGION/$PROJECT_NAME/container-web/$CONTAINER_WEB_NAME"
PAYLOAD='{
"spec": {
"image": "${{env.ACR_PATH}}:${{env.SNAPSHOT_VERSION}}",
"secrets": {
"key_vaults": [
{
"name": "${{env.KEY_VAULT}}",
"secrets": [
{
"name": "mysql-pwd",
"environment_variable": "mysql_pwd"
},
]
}
],
},
}
}'
curl --location --request PUT 'https://abcd/us/projects/tirumalesh-automate/resources/container-web/configuration-service' \
--header "$AUTH_HEADER" \
--header 'Content-Type: application/json' \
--data-raw "$PAYLOAD"
You have single quotes around PAYLOAD, which means that it will take the string literally and not expand anything.
Use double quotes and escape the quotes.
PAYLOAD="{
\"spec\": {
\"image\": \"${{env.ACR_PATH}}:${{env.SNAPSHOT_VERSION}}\",
\"secrets\": {
\"key_vaults\": [
{
\"name\": \"${{env.KEY_VAULT}}\",
\"secrets\": [
{
\"name\": \"mysql-pwd\",
\"environment_variable\": \"mysql_pwd\"
},
]
}
],
},
}
}"
curl --location --request PUT 'https://abcd/us/projects/tirumalesh-automate/resources/container-web/configuration-service' \
--header "$AUTH_HEADER" \
--header 'Content-Type: application/json' \
--data-raw "$PAYLOAD"

What is the format of the JSON for a Jenkins REST buildWithParameters to override the default parameters values

I am able to build a Jenkins job with its parameters' default values by sending a POST call to
http://jenkins:8080/view/Orion_phase_2/job/test_remote_api_triggerring/buildWithParameters
and I can override the default parameters "product", "suites" and "markers by sending to this URL:
http://jenkins:8080/view/Orion_phase_2/job/test_remote_api_triggerring/buildWithParameters?product=ALL&suites=ALL&markers=ALL
But I saw examples were the parameters can be override by sending a JSON body with new values. I am trying to do that by sending the following json bodies. Neither of them works for me.
{
'product': 'ALL',
'suites': 'ALL',
'markers': 'ALL'
}
and
{
"parameter": [
{
"name": "product",
"value": "ALL"
},
{
"name": "suites",
"value": "ALL"
},
{
"name": "markers",
"value": "ALL"
}
]
}
What JSON to send if I want to override the values of parameters "product", "suites" & "markers"?
I'll leave the original question as is and elaborate here on the various API calls to trigger parameterized builds. These are the calls options that I used.
Additional documentation: https://wiki.jenkins.io/display/JENKINS/Remote+access+API
The job contains 3 parameters named: product, suites, markers
Send the parameters as URL query parameters to /buildWithParameters:
http://jenkins:8080/view/Orion_phase_2/job/test_remote_api_triggerring/buildWithParameters?product=ALL&suites=ALL&markers=ALL
Send the parameters as JSON data\payload to /build:
http://jenkins:8080/view/Orion_phase_2/job/test_remote_api_triggerring/build
The JSON data\payload is not sent as the call's json_body (which is what confused me), but rater in the data payload as:
json:'{
"parameter": [
{"name":"product", "value":"123"},
{"name":"suites", "value":"high"},
{"name":"markers", "value":"Hello"}
]
}'
And here are the CURL commands for each of the above calls:
curl -X POST -H "Jenkins-Crumb:2e11fc9...0ed4883a14a" http://jenkins:8080/view/Orion_phase_2/job/test_remote_api_triggerring/build --user "raameeil:228366f31...f655eb82058ad12d" --form json='{"parameter": [{"name":"product", "value":"123"}, {"name":"suites", "value":"high"}, {"name":"markers", "value":"Hello"}]}'
curl -X POST \
'http://jenkins:8080/view/Orion_phase_2/job/test_remote_api_triggerring/buildWithParameters?product=234&suites=333&markers=555' \
-H 'authorization: Basic c2hsb21pb...ODRlNjU1ZWI4MjAyOGFkMTJk' \
-H 'cache-control: no-cache' \
-H 'jenkins-crumb: 0bed4c7...9031c735a' \
-H 'postman-token: 0fb2ef51-...-...-...-6430e9263c3b'
What to send to Python's requests
In order to send the above calls in Python you will need to pass:
headers = jenkins-crumb
auth = tuple of your (user_name, user_auth_token)
data = dictionary type { 'json' : json string of {"parameter":[....]} }
curl -v POST http://user:token#host:port/job/my-job/build --data-urlencode json='{"parameter": [{"name":"xx", "value":"xxx"}]}
or use Python request:
import requests
import json
url = " http://user:token#host:port/job/my-job/build "
pyload = {"parameter": [
{"name":"xx", "value":"xxx"},
]}
data = {'json': json.dumps(pyload)}
rep = requests.post(url, data)

wso2am API manager 2.1 publisher change-lifecycle issue

I deployed API Manager 2.1.0 and setup the api-import-export-2.1.0 war file described here. After importing my API endpoint by uploading a zip file the status=CREATED.
To actually publish the API I am calling the Publisher's change-lifecycle API but I am getting this exception:
TID: [-1234] [] [2017-07-06 11:11:57,289] ERROR
{org.wso2.carbon.apimgt.rest.api.util.exception.GlobalThrowableMapper}
- An Unknown exception has been captured by global exception mapper.
{org.wso2.carbon.apimgt.rest.api.util.exception.GlobalThrowableMapper}
java.lang.NoSuchMethodError:
org.wso2.carbon.apimgt.api.APIProvider.changeLifeCycleStatus(Lorg/wso2/carbon/apimgt/api/model/APIIdentifier;Ljava/lang/String;)Z
Any ideas on why?
I can get an access token (scope apim:api_view) and call this
:9443/api/am/publisher/v0.10/apis
to list the api's just fine.
I get a different acces_token (for scope: apim:api_publish) and then call
:9443/api/am/publisher/v0.10/apis/change-lifecycle
but get the above Exception. Here's the example:
[root#localhost] ./publish.sh
View APIs (token dc0c1497-6c27-3a10-87d7-b2abc7190da5 scope: apim:api_view)
curl -k -s -H "Authorization: Bearer dc0c1497-6c27-3a10-87d7-b2abc7190da5" https://gw-node:9443/api/am/publisher/v0.10/apis
{
"count": 1,
"next": "",
"previous": "",
"list": [
{
"id": "d214f784-ee16-4067-9588-0898a948bb17",
"name": "Health",
"description": "health check",
"context": "/api",
"version": "v1",
"provider": "admin",
"status": "CREATED"
}
] }
Publish API (token b9a31369-8ea3-3bf2-ba3c-7f2a4883de7d scope: apim:api_publish)
curl -k -H "Authorization: Bearer b9a31369-8ea3-3bf2-ba3c-7f2a4883de7d" -X POST https://gw-node:9443/api/am/publisher/v0.10/apis/change-lifecycle?apiId=d214f784-ee16-4067-9588-0898a948bb17&action=Publish
{
"code":500,
"message":"Internal server error",
"description":"The server encountered an internal error. Please contact administrator.",
"moreInfo":"",
"error":[]
}
Issue resolved. In apim 2.1 the publisher & store API versions changed.
In apim 2.0 I was using:
:9443/api/am/publisher/v0.10/apis
:9443/api/am/store/v0.10/apis
but in apim 2.1 they are:
:9443/api/am/publisher/v0.11/apis
:9443/api/am/store/v0.11/apis

Invalid Scope error while retrieving an Authentication token for creating a skype bot

As per the article below, I am trying to retrieve a token for creating a Skype bot.
Article:
https://docs.botframework.com/en-us/restapi/authentication#authentication-technologies
Command used:
curl -X POST -H "Cache-Control: no-cache" -H "Content-Type: application/x-www-form-urlencoded"
-d 'client_id=<your-app-id>&client_secret=<your-app-secret>&grant_type=client_credentials&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default'
'https://login.microsoftonline.com/common/oauth2/v2.0/token'
Error:
{
"error": "invalid_scope",
"error_description":
"AADSTS70011: The provided value for the input
parameter 'scope' is not valid. The scope https%3A%2F%2Fgraph.microsoft.com%2F.default is not valid.\r\n
Trace ID: 43082e14-9e0b-4a2c-a532-47d0a55a50a4\r\n
Correlation ID: 6c79b873-9e28-4842-8803-15e4c25af1e3\r\n
Timestamp: 2016-09-06 05:27:16Z",
"error_codes": [
70011
],
"timestamp": "2016-09-06 05:27:16Z",
"trace_id": "43082e14-9e0b-4a2c-a532-47d0a55a50a5",
"correlation_id": "6c79b873-9e28-4842-8803-15e4c25af1e6"
}