I'm trying to activate OSPF routing protocol in a router using a python script with restconf. I send the request to this url https://(router ip)/restconf/data/Cisco-IOS-XE-ospf-native-router:10 but i get this return message: { "errors": { "error": [ { "error-message": "uri keypath not found", "error-tag": "invalid-value", "error-type": "application" } ] } }
I tried with differents urls but no one was the correct and i don't know what is wrong, the url or the content of the body , can someone help me?
This is the content of my script:
import json
import requests
requests.packages.urllib3.disable_warnings()
api_url = "https://(ip)/restconf/data/Cisco-IOS-XE-ospf-native-router:10"
headers = {"Accept": "application/yang-data+json",
"Content-type": "application/yang-data+json"}
basicauth = ("user", "password")
body = '{"router":{"ospf":[{"id":10, "router-id":"1.1.1.1", "network":[{"ip": "172.16.199.1", "mask": "0.0.0.0", "area": 0},{"ip":"192.168.56.101", "mask": "0.0.0.0", "area":0}]}]}}'
requests.put(api_url, auth=basicauth, headers=headers, data=body, verify=False)
resp = requests.get(api_url, auth=basicauth, headers=headers, verify=False)
response_json = resp.json()
print(json.dumps(response_json, indent=5))
OSPF config with RESTCONF can just be modify, not create.
ospf_data = '''
{
"Cisco-IOS-XE-native:router": {
"Cisco-IOS-XE-ospf:router-ospf": {
"ospf": {
"process-id": [
{
"id": 10
}
]
}
}
}
}
'''
def modify_ospf(data):
ospf_api = "/restconf/data/Cisco-IOS-XE-native:native/router"
ospf_uri = "https://" + host + ospf_api
headers = {'Content-Type': 'application/yang-data+json','Accept': 'application/yang-data+json'}
ospf_config_result = requests.request("PUT",
url=ospf_uri,
auth=(username,password),
data=data,
headers=headers,
verify=False)
modify_ospf(ospf_data)
Your body seems not vaild YANG format.
body = '{"router":{"ospf":[{"id":10, "router-id":"1.1.1.1", "network":[{"ip": "172.16.199.1", "mask": "0.0.0.0", "area": 0},{"ip":"192.168.56.101", "mask": "0.0.0.0", "area":0}]}]}}'
You have to follow YANG format like:
$ curl -k -s -u user:password -X GET -H 'Accept: application/yang-data+json' https://172.31.5.1/restconf/data/Cisco-IOS-XE-native:native/Cisco-IOS-XE-native:router/ospf
{
"Cisco-IOS-XE-ospf:ospf": [
{
"id": 10,
"router-id": "1.1.1.1",
"network": [
{
"ip": "172.16.199.1",
"mask": "0.0.0.0",
"area": 0
},
{
"ip": "192.168.56.101",
"mask": "0.0.0.0",
"area": 0
}
]
}
]
}
Related
I need to create records in an airtable base and have the following code in scrapy:
url = "https://api.airtable.com/v0/appuhKmlhLIIEszLm/Table%201"
payload = json.dumps({
"records": [
{
"fields": {
"Name": "Temporada 6"
}
},
{
"fields": {
"Name": "Temporada 2"
}
}
]
})
headers = {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
}
yield scrapy.Request(method = "POST",url = url, headers=headers, body=payload)
I checked the code with python requests and works, however, when I use this scrapy code, no info is uploaded, do you know why is this?
I can't figure out how to set up an API correctly. I have an example in Python and would like to understand how to reproduce it
with R, how to correctly choose attributes and authenticate.
import requests
import json
url = "https://developer.junglescout.com/api/product_database_query?marketplace=us"
payload = json.dumps({
"data": {
"type": "product_database_query",
"attributes": {
"include_keywords": [
"videogames"
],
"categories": [
"Video Games"
],
"exclude_unavailable_products": True
}
}
})
headers = {
'Content-Type': 'application/vnd.api+json',
'Accept': 'application/vnd.junglescout.v1+json',
'Authorization': 'KEY_NAME:MY_API_KEY'
}
response = requests.request("POST", url, headers=headers, data=payload)
I have a reverse proxy server with NGINX and I want to test its configuration automatically.
What I want to achieve in the end is to have a command that I can run, it starts the NGINX with the configuration, run several http requests, and then track and gather whether the right proxied server was called.
I've been thinking on setting up an environment with docker-compose and use curl/wget with the list of urls I want to test. The thing that I don't know is how to mock certain domains and track the forwarded requests.
Is there a tool to do that or should I write a server manually?
After experimenting a bit I managed to create this solution.
Use Docker Compose, Wiremock and Newman. The idea is to setup NGINX proxying requests to Wiremock (where you can control if the request matched the right structure), then with Newman, you can run a Postman collection that automatically checks that the stubbed responses are the right ones.
Example
Create all these files in a folder, get the testing environment by running
docker-compose up -d nginx wiremock
and then, to run the test suite
docker-compose run --rm newman
It should print the results of the collection.
Files
docker-compose.yml
version: "3"
services:
nginx:
image: nginx
ports:
- "80:80"
volumes:
- ./config:/etc/nginx
wiremock:
image: wiremock/wiremock:2.32.0
command: [ "--port", "80", "--verbose" ]
ports:
- "8080:80"
volumes:
- ./wiremock:/home/wiremock
networks:
default:
aliases:
- backend-service-1
- backend-service-2
newman:
image: postman/newman
volumes:
- ./newman:/etc/newman
command: [ "run", "example.postman_collection.json" ]
config/nginx.conf
events {
worker_connections 1024;
}
http {
resolver 127.0.0.11; # docker internal resolver
server {
listen 80 default_server;
location /some/path/ {
proxy_set_header X-Forwarded-Host $host;
proxy_pass http://backend-service-1/some/path;
}
location /other/path/ {
proxy_set_header X-Forwarded-Host $host;
proxy_pass http://backend-service-2/other/path;
}
}
}
wiremock/mappings/some-path.json
{
"request": {
"method": "GET",
"url": "/some/path",
"headers": {
"Host": {
"equalTo": "backend-service-1",
"caseInsensitive": true
}
}
},
"response": {
"status": 200,
"body": "{\"host\": \"from-1\"}",
"headers": {
"Content-Type": "application/json"
}
}
}
wiremock/mappings/other-path.json
{
"request": {
"method": "GET",
"url": "/other/path",
"headers": {
"Host": {
"equalTo": "backend-service-2",
"caseInsensitive": true
}
}
},
"response": {
"status": 200,
"body": "{\"host\": \"from-2\"}",
"headers": {
"Content-Type": "application/json"
}
}
}
newman/example.postman_collection.json
{
"info": {
"name": "example",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "some path",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"request backend service 1\", function () {",
" pm.response.to.have.status(200);",
"",
" var jsonData = pm.response.json();",
" pm.expect(jsonData.host).to.eql(\"from-1\");",
"});",
""
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://nginx/some/path/",
"protocol": "http",
"host": [
"nginx"
],
"path": [
"some",
"path",
""
]
}
},
"response": []
},
{
"name": "other path",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"request backend service 2\", function () {",
" pm.response.to.have.status(200);",
"",
" var jsonData = pm.response.json();",
" pm.expect(jsonData.host).to.eql(\"from-2\");",
"});",
""
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://nginx/other/path/",
"protocol": "http",
"host": [
"nginx"
],
"path": [
"other",
"path",
""
]
}
},
"response": []
}
]
}
I'm trying to upload a video > 200MB via https://api.linkedin.com/v2/assets. When registering a MULTIPART_UPLOAD I do not receive the "x-amz-server-side-encryption" or "x-amz-server-side-encryption-aws-kms-key-id" headers information anywhere in the response. I do get those when registering a SINGLE_REQUEST_UPLOAD and I'm able to successfully upload a video file < 200MB using that mechanism.
Example response for registering a multi-part upload:
{
"value": {
"uploadMechanism": {
"com.linkedin.digitalmedia.uploading.MultipartUpload": {
"metadata": "{METADATA}",
"partUploadRequests": [
{
"headers": {
"Content-Length": "5242880",
"Content-Type": "application/octet-stream"
},
"urlExpiresAt": 1547231882996,
"byteRange": {
"lastByte": 5242879,
"firstByte": 0
},
"url": "{AWS_UPLOAD_URL}"
},
{
"headers": {
"Content-Length": "5242880",
"Content-Type": "application/octet-stream"
},
"urlExpiresAt": 1547231882996,
"byteRange": {
"lastByte": 10485759,
"firstByte": 5242880
},
"url": "{AWS_UPLOAD_URL}"
},
{
"headers": {
"Content-Length": "3585789",
"Content-Type": "application/octet-stream"
},
"urlExpiresAt": 1547231883023,
"byteRange": {
"lastByte": 580302588,
"firstByte": 576716800
},
"url": "{AWS_UPLOAD_URL}"
}
]
}
},
"mediaArtifact": "urn:li:digitalmediaMediaArtifact:(urn:li:digitalmediaAsset:{ASSET_URN},urn:li:digitalmediaMediaArtifactClass:aws-userUploadedVideo)",
"asset": "urn:li:digitalmediaAsset:{ASSET_URN}"
}
}
I have tried to upload to those urls without the two headers and get a 403 Forbidden response saying I'm missing signed headers. The "x-amz-server-side-encryption" and "x-amz-server-side-encryption-aws-kms-key-id" should be returned in the register response right? If not, how do I make requests to aws without them?
I am trying to request data using the httr package. Following this format:
args <- list(metrics = c(list(name = "Jobs.2018",as = "Jobs 2018")),
constraints = list(dimensionName ="Area",
map = list("Latah County ID" = c(16057))))
test <- POST(url =
"https://agnitio.emsicloud.com/emsi.us.demographics/2018.3",
add_headers(`authorization` = paste("bearer",token)),
add_headers(`content-type` ="application/json"),
body = toJSON(args,auto_unbox = TRUE),
verbose())
I keep getting a 400 Bad Request error with everything I have looked up and tried. Do I need to add something to the arguments that I am just not finding?
P.S. I am sorry that this isn't a repeatable example
We'll assume (a bad thing but necessary for an answer) that you obtained token by issuing a prior POST request as indicated on the linked API page and then properly decoded the JSON web token into token.
If you did that properly, then one next likely possibility is malformed body data in POST request.
When I look at a sample API call:
curl --request POST \
--url https://agnitio.emsicloud.com/emsi.us.industry/2018.3 \
--header 'authorization: bearer <access_token>' \
--header 'content-type: application/json' \
--data '{ "metrics": [ { "name": "Jobs.2017", "as":"2017 Jobs" }, { "name": "Establishments.2017" } ], "constraints": [ { "dimensionName": "Area", "map": { "Latah County, ID": ["16057"] } }, { "dimensionName": "Industry", "map": { "Full Service Restaurant s": ["722511"] } } ] }'
that sample JSON looks like this pretty-printed:
{
"metrics": [
{
"name": "Jobs.2017",
"as": "2017 Jobs"
},
{
"name": "Establishments.2017"
}
],
"constraints": [
{
"dimensionName": "Area",
"map": {
"Latah County, ID": [
"16057"
]
}
},
{
"dimensionName": "Industry",
"map": {
"Full Service Restaurants": [
"722511"
]
}
}
]
}
Yours looks like:
{
"metrics": {
"name": "Jobs.2018",
"as": "Jobs 2018"
},
"constraints": {
"dimensionName": "Area",
"map": {
"Latah County ID": 16057
}
}
}
when it needs to look more like this:
{
"metrics": [
{
"name": "Jobs.2018",
"as": "Jobs 2018"
}
],
"constraints": [
{
"dimensionName": "Area",
"map": {
"Latah County ID": [
"16057"
]
}
}
]
}
To do that, we need to use this list structure:
list(
metrics = list(
list(
name = jsonlite::unbox("Jobs.2018"),
as = jsonlite::unbox("Jobs 2018")
)),
constraints = list(list(
dimensionName = jsonlite::unbox("Area"),
map = list("Latah County ID" = c("16057"))
))
) -> args
Note especially that the API expects that map ID JSON data element to be character and not integer/numeric.
Now, we can make the POST request like this (spaced out for answer readability as it has embedded comments):
httr::POST(
url = "https://agnitio.emsicloud.com/emsi.us.demographics/2018.3",
httr::add_headers(
`authorization` = sprintf("bearer %s", token)
),
encode = "json", # this lets' httr do the work for you
httr::content_type_json(), # easier than making a header yourself
body = args,
httr::verbose()
) -> res
That should work but b/c it's a closed API without free registration I cannot test it.