I'm trying to make an api call to k8s api server to update deployment. I can use below to update deployment.
curl -X PATCH --header "Authorization: Bearer $TOKEN" --insecure -H 'Content-Type: application/strategic-merge-patch+json' --data '
{ "spec": { "template": { "spec": { "containers": [ { "name": "nlu","env": [ { "name": "LAST_UPDATE", "value": "123123" } ] } ] } } } }' \
'https://10.1.0.4:6443/apis/apps/v1/namespaces/prod/deployments/nlu?fieldManager=strategic'
But when I use the node.js request module to make request, I got an error like below
message:"read ECONNRESET"
Here is my code
restart()
{
const options = {
url: "http://10.1.0.4:6443",
body: JSON.stringify({
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "nlu",
"env": [
{
"name": "LAST_UPDATE",
"value": "20190909"
}
]
}
]
}
}
}
}),
auth: {
'bearer': "mytoken"
}
};
return new Promise(function(resolve,reject){
request.patch(options, (err , res)=>{
if(err)
{
reject(err)
} else
{
resolve('done')
}
})
})
}
How can I fix this problem, any help would be appreciated?
I found out I missed something so that the k8s server rejected my request. First, the url should start with https instead of http. Second, I was supposed to add content-type "application/strategic-merge-patch+json" in the request head. Third, I also have to add rejectUnauthorized: false in the request to ignore the error when failing to verify the server's identity.
The correct request should be like
const options = {
url: "https://10.1.0.4:6443",
headers: {
"content-type": "application/strategic-merge-patch+json"
},
rejectUnauthorized: false,
body: JSON.stringify({
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "nlu",
"env": [
{
"name": "LAST_UPDATE",
"value": "20190909"
}
]
}
]
}
}
}
}),
auth: {
'bearer': "mytoken"
}
};
Related
I am building out a new endpoint in my application which uses express-openapi-validator as validator middleware.
/* index.ts */
import * as OpenApiValidator from 'express-openapi-validator';
const whitelistedPaths = [/* regex tested paths */];
app.use(
OpenApiValidator.middleware({
apiSpec: './schema/api.json',
validateResponses: true,
ignorePaths: whitelistedPaths,
validateSecurity: true,
}),
);
/* ... */
app.post(
'/users/:email/validateToken',
bodyParser.json(),
(req) => validateToken(req.params.email, req.body.resetToken),
);
In my configuration (api.json) file I've defined the schema for my endpoint as:
"/users/{email}/validateToken": {
"post": {
"tags": ["users"],
"summary": "Validate user token",
"operationId": "validateToken",
"responses": {
"200": {
"description": "Ok",
"content": {
"application/json": {
"schema": {}
}
}
}
},
"parameters": [
{
"name": "email",
"in": "path",
"description": "User email",
"schema": {
"type": "string"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["resetToken"],
"properties": {
"resetToken": {
"type": "string"
}
}
}
}
}
}
}
},
I've tested with Postman with the following JSON body:
{
"resetToken": "randomd9320ru9"
}
but receive the following error message:
{
"message": "request should have required property 'body'",
"errors": [
{
"path": ".body",
"message": "should have required property 'body'",
"errorCode": "required.openapi.validation"
}
]
}
I'm not sure why it's complaining about the body. I tried putting "required": true under the requestBody config in api.json but that didn't change anything. I just want to make sure that the body includes the required field resetToken.
I suppose you need to use bodyParser.json() before using OpenApiValidator.middleware:
app.use(bodyParser.json());
app.use(
OpenApiValidator.middleware({
apiSpec: './schema/api.json',
validateRequests: true,
validateResponses: true,
ignorePaths: whitelistedPaths,
validateSecurity: true,
}),
);
...
app.post(
'/users/:email/validateToken',
(req) => validateToken(req.params.email, req.body.resetToken),
);
When using a text file, this works like a regular GET
{
"responses": [
{
"is": {
"headers": {
"content-disposition": "attachment; filename=sample_text_file.txt"
},
"statusCode": 200,
"body": "<%- stringify(filename, 'templates/attachments/sample_text_file.txt') %>"
}
}
],
"predicates": [
{
"and": [
{
"equals": {
"method": "GET",
"path": "/resources/4df3dab6-003b-440d"
}
}
]
}
]
}
However, when an image file is used in place of text file, the Mountebank fails to start.
I'm trying to make a healthcheck for my service in New Relic. So I just want to call one of my APIs every x minutes and see if it returns 200.
In New Relic I created a new synthetic monitor and now I'm trying to write a script for that monitor.
The script is supposed to make a post request to our service and receive a token in the response with status 200. In Postman this post request works and returns the token + Status 200 (I replaced the sensitive strings with <...>):
curl --location --request POST <TOKEN_URL> \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=<CLIENT_ID_DEV>' \
--data-urlencode 'client_secret=<CLIENT_SECRET_DEV>'
But when I try to recreate that with the script, it always returns Status 400 Bad Request.
This is my script:
var assert = require('assert');
//Defining my authentication credentials.
var IDK_TOKEN_URL = $secure.TOKEN_URL;
var CLIENT_ID = $secure.CLIENT_ID_DEV;
var CLIENT_SECRET = $secure.CLIENT_SECRET_DEV;
var options = {
url: IDK_TOKEN_URL,
body: JSON.stringify({
grant_type: 'client_credentials',
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
}),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
//Define expected results using callback function.
function callback(error, response, body) {
console.log(response.statusCode + " status code")
assert.ok(response.statusCode == 200, 'Expected 200 OK response');
var info = JSON.parse(body);
assert.ok(info.success == true, 'Expected True results in Response Body, result was ' + info.success);
console.log("End reached");
}
//Make POST request, passing in options and callback.
$http.post(options, callback);
This is what I see in the console:
It seems to automatically append a port 443 to my url, so instead of <my url>.io/oidc/v1/token, the request seems to get fired to <my url>.io:443/oidc/v1/token?
And when I click on "View resource" in the image above, I see:
But I'm using a post method, why is it saying anything about get method is not allowed?
This is the HAR log that I can download in the new relic console:
"request": {
"cookies": [],
"headers": [
{
"name": "Content-Type",
"value": "application/x-www-form-urlencoded"
},
{
"name": "host",
"value": "<my url>.io"
},
{
"name": "content-length",
"value": "187"
},
{
"name": "X-Abuse-Info",
"value": "Request sent by a New Relic Synthetics Monitor (https://docs.newrelic.com/docs/synthetics/new-relic-synthetics/administration/identify-synthetics-requests-your-app) - monitor id: df1817f0-fac2-49f4-a0d5-479d254dfa1a | account id: 2807718"
},
{
"name": "X-NewRelic-Synthetics",
"value": "[1,2807718,\"fddc843c-8fe0-497f-bf5b-52c2805a265e\",\"b6da79b9-37ab-4a8a-a792-f3fa0f99f205\",\"df1817f0-fac2-49f4-a0d5-479d254dfa1a\"]"
}
],
"headersSize": 607,
"bodySize": 187,
"method": "POST",
"url": "<my url>.io:443/oidc/v1/token/",
"httpVersion": "HTTP/1.1",
"queryString": [],
"postData": {
"mimeType": "application/x-www-form-urlencoded",
"text": "{\"grant_type\":\"client_credentials\",\"client_id\":\"_SECURECREDENTIAL_\",\"client_secret\":\"_SECURECREDENTIAL_\"}",
"params": []
},
"_ajax": false,
"_mixedContentType": "unknown",
"_referrerPolicy": "",
"_isLinkPreload": false,
"_host": "<my url>.io",
"_port": 443,
"_path": "/oidc/v1/token/"
},
"response": {
"cookies": [],
"headers": [
{
"name": "Date",
"value": "Thu, 06 May 2021 10:21:05 GMT"
},
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Content-Length",
"value": "67"
},
{
"name": "Connection",
"value": "close"
},
{
"name": "Cache-Control",
"value": "no-cache, no-store, max-age=0, must-revalidate"
},
{
"name": "Expires",
"value": "0"
},
{
"name": "Pragma",
"value": "no-cache"
},
{
"name": "Referrer-Policy",
"value": "origin"
},
{
"name": "Strict-Transport-Security",
"value": "max-age=31536000 ; includeSubDomains"
},
{
"name": "Vary",
"value": "accept-encoding,origin,access-control-request-headers,access-control-request-method,accept-encoding"
},
{
"name": "X-Content-Type-Options",
"value": "nosniff"
},
{
"name": "X-Frame-Options",
"value": "DENY"
},
{
"name": "X-Vcap-Request-Id",
"value": "e2006a3c-0c27-4194-6b81-d9f037158ca3"
},
{
"name": "X-Xss-Protection",
"value": "1; mode=block"
}
],
"headersSize": 544,
"bodySize": 67,
"status": 400,
"statusText": "Bad Request",
"httpVersion": "HTTP/1.1",
"content": {
"size": 639,
"compression": 572,
"mimeType": "application/json",
"text": ""
},
"redirectURL": "",
"_chromeStatusText": "Bad Request",
"_connectionReused": false,
"_fromServiceWorker": false,
"_fromDiskCache": false,
"_fromAppCache": false,
"_fromCache": false
},
I had to replace 'body' with 'form' like in this example.
I aslo added now the call to the API after the token was received. The final script was:
var assert = require('assert');
//Define your authentication credentials.
var TOKEN_URL = $secure.TOKEN_URL;
var MY_SERVICE_BASE_URL = $secure.MY_SERVICE_BASE_URL_DEV;
var CLIENT_ID = $secure.CLIENT_ID_DEV;
var CLIENT_SECRET = $secure.CLIENT_SECRET_DEV;
function new_relic_callback(err, response, body) {
assert.equal(response.statusCode, 200, 'Expected a 200 OK response');
};
function api_request_callback(err, response, body) {
var parsed_body = JSON.parse(body);
var api_request = {
url: CONSENT_BASE_URL + '/rest of URL...',
headers: {
'Authorization': 'Bearer ' + parsed_body["access_token"]
}
};
$http.get(api_request, new_relic_callback);
};
var token_request = {
url: TOKEN_URL,
form: {
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
grant_type: "client_credentials"
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
$http.post(token_request, api_request_callback);
I have below code and looks like it is not checking headers as a predicate.
{
"responses": [
{
"inject": "<%- stringify(filename, 'Scripts/MyDept/CutOffTime.ejs') %>"
}
],
"predicates": [
{
"matches": {
"method": "GET",
"path": "/cutoff-times",
"query": {
"country": "\\w+"
},
"headers": {
"X-CLIENT-ID": "^[ A-Za-z0-9]*$"
}
}
}
]
}
Strangely, when I pass # as the value to header X-CLIENT-ID it validate and shows the message as no predicate match. Because it is not part of the regex.
Identified the issue,
Basically if you need have multiple predicates need to merge them as below,(using and / or)
{
"responses": [
{
"inject": "<%- stringify(filename, 'Scripts/MyDept/CutOffTime.ejs') %>"
}
],
"predicates": [
{
"and": [
{
"exists": {
"headers": {
"X-CLIENT-ID": true,
}
}
},
{
"matches": {
"method": "GET",
"path": "/cutoff-times",
"headers": {
"X-CLIENT-ID": "^[ A-Za-z0-9]*$"
},
"query": {
"country": "\\w+"
}
}
}
]
}
]
}
Mountebank site
Further matches predicate doesn't check the existence (e.g. header existence)
I am getting an 500 error 'unexpected problem has occurred' when I parse the GeoJSON data from this weather API site using node app.
The code is a simple proxy server to receive request from client for weather info on a particular site and process an async request to the weatherAPI, when the response is received its send to the client. When I replace the URL with something that returns JSON it works. The issue is when the response data is GeoJSON.
Appreciate if anyone help shed some light on how to parse the GeoJSON response in node JavaScript.
Thank you in advance.
Here is my node app code:
function initialize() {
// Setting URL and headers for request
var options = {
url: 'https://api.weather.xxx/points/39.7456,-97.0892',
headers: {
'User-Agent': 'request'
}
};
// Return new promise
return new Promise(function(resolve, reject) {
// Do async job
request.get(options, function(err, resp, body) {
if (err) {
reject(err);
} else {
resolve(JSON.parse(body));
}
})
})
}
http.createServer(function (req, res) {
var initializePromise = initialize();
initializePromise.then(function(result) {
var geoDetails = result;
console.log("Initialized Geo details");
// Use user details from here
console.log(geoDetails);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied!' + '\n' +
JSON.stringify(geoDetails, true, 2));
res.end();
}, function(err) {
console.log(err);
})
}).listen(9000);
Here is the GeoJSON data :
{
"#context": [
"...",
{
"wx": "...",
"s": "...",
"geo": "...",
"unit": "...",
"#vocab": "...",
"geometry": {
"#id": "s:GeoCoordinates",
"#type": "geo:wktLiteral"
},
"city": "s:addressLocality",
"state": "s:addressRegion",
"distance": {
"#id": "s:Distance",
"#type": "s:QuantitativeValue"
},
"bearing": {
"#type": "s:QuantitativeValue"
},
"value": {
"#id": "s:value"
},
"unitCode": {
"#id": "s:unitCode",
"#type": "#id"
},
"forecastOffice": {
"#type": "#id"
},
"forecastGridData": {
"#type": "#id"
},
"publicZone": {
"#type": "#id"
},
"county": {
"#type": "#id"
}
}
],
"id": "...api.weather.xxx/points/39.7456,-97.0892",
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-97.0892,
39.7456
]
},
"properties": {
"#id": "...api.weather.xxx/points/39.7456,-97.0892",
"#type": "wx:Point",
"cwa": "TOP",
"forecastOffice": "...api.weather.xxx/offices/TOP",
"gridX": 31,
"gridY": 80,
...
"relativeLocation": {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-97.086661,
39.679376
]
},
"properties": {
"city": "Linn",
"state": "KS",
"distance": {
"value": 7366.9851976444,
"unitCode": "unit:m"
},
"bearing": {
"value": 358,
"unitCode": "unit:degrees_true"
}
}
},
...
}
}
I am interested in getting all the Properties in plain text or JSON.
Modify your headers to accept JSON.
var options = {
url: 'https://api.weather.gov/points/39.7456,-97.0892',
headers: {
'user-agent': 'request',
'accept': 'application/json'
}
};