How can i update a jenkins job using the api - api

I have to create/update a jenkins job using its api because all of my jobs are using parameters which are also used by other scripts and I am trying to centralize the scripts so when i change it in one place, the change reflects in all.
currently, if someone changes the script, they they also have to manually edit the parameters of the jenkins job as well.
I saw the example of the Remote API for creating jobs and was able to successfully create test jobs but how can i edit an existing job besides deleting it and creating it again(which isnt an option as i have to maintain the build history).

You could use python like this:
from jenkinsapi.jenkins import Jenkins
jenkinsSource = 'http://10.52.123.124:8080/'
server = Jenkins(jenkinsSource, username = 'XXXXX', password = 'YYYYY')
myJob=server.get_job("__test")
myConfig=myJob.get_config()
print myConfig
new = myConfig.replace('<string>clean</string>', '<string>string bean</string>')
myJob.update_config(new)

in case anyone else is also looking for the same answer,
It appears the solution is far easier, all you have to do is update the config.xml and post the updated config.xml back to jenkins and your job will be updated.

You can also POST an updated config.xml to the URL which can fetch config.xml, to programmatically update the configuration of a job.
The fetch url pattern: $JENKINS_SERVER/job/$JOB_NAME/config.xml
detailed doc pattern: $JENKINS_SERVER/job/$JOB_NAME/api
example: https://ci.jenkins-ci.org/job/infra_atlassian-base/api/

http://asheepapart.blogspot.ca/2014/03/use-jenkins-rest-api-to-update-job.html
That little bit of scripting looks to be what you are looking for. Uses the REST API to get and set the config with some regex S&R in the middle.
Edit: Code below based on comment. It is copied directly from the blog so I take no credit for it.
# First, get the http://jenkins.example.com/job/folder-name/job/sample-job--template/configure looking like you want
read -s token
# type token from http://jenkins.example.com/user/$userName/configure
# Download the configuration XML for the template job (which will be our model template)
curl -v -u "bvanevery:$token" http://jenkins.example.com/job/folder-name/job/sample-job--template/config.xml > generic-config.xml
# My modules
declare modules=('module1' 'module2' 'module3')
# POST the updated configuration XML to Jenkins
for m in ${modules[#]}; do
echo "module $m";
sed "s/MODULE/$m/g" generic-config.xml > $m-config.xml;
curl -v -X POST --data-binary #$m-config.xml -u "bvanevery:$token" \
-H 'Content-Type: application/xml' \
"http://jenkins.example.com/job/folder-name/job/$m/config.xml" ;
done

For those using RestSharp, I found that I needed to make sure that:
The user ID performing the update had permission to do so under Manage > Global Security > Authorization Matrix
I had a current Jenkins Crumb token, required once CSRF (also under Manage > Security) is enabled.
Send the updated XML using a parameter of the Request object with the value of [ParameterType.RequestBody] (link)1 for the type argument.
private XmlDocument JobConfigGet()
{
Uri JobConfigURI = GetJenkinsURI("job/" + _args.JobName + "/config.xml", null);
RestClient restClient = new RestClient(JobConfigURI);
RestRequest restRequest = new RestRequest(Method.GET);
byte[] ua = Encoding.ASCII.GetBytes(Properties.Settings.Default.UserID + ":" + Properties.Settings.Default.UserPassword);
restRequest.AddHeader("authorization", "Basic " + Convert.ToBase64String(ua));
IRestResponse restResponse = restClient.Execute(restRequest);
if (restResponse.ResponseStatus != ResponseStatus.Completed || restResponse.StatusCode != HttpStatusCode.OK)
throw new Exception(string.Format("Unable to retrieve job config: {0}. Wrong ResponseStatus ({1}) or StatusCode ({2}) returned.\nURL: {3}", _args.JobName, restResponse.ResponseStatus.ToString(), restResponse.StatusCode.ToString(), restClient.BaseUrl.AbsoluteUri));
if (restResponse.ContentType != "application/xml")
throw new Exception("Unexpected data type returned for job config: " + _args.JobName + ". Expected 'application/xml'. Got: " + restResponse.ContentType + ".\nURL: " + restClient.BaseUrl.AbsoluteUri);
XmlDocument jobConfig = new XmlDocument();
jobConfig.LoadXml(restResponse.Content);
return jobConfig;
}
private void JobConfigUpdate(XmlDocument JobConfig, string JenkinCrumb)
{
// Update JobConfig XML as needed here.
Uri JobConfigURI = GetJenkinsURI("job/" + _args.JobName + "/config.xml", null);
RestClient restClient = new RestClient(JobConfigURI);
RestRequest restRequest = new RestRequest(Method.POST);
byte[] ua = Encoding.ASCII.GetBytes(Properties.Settings.Default.UserID + ":" + Properties.Settings.Default.UserPassword);
restRequest.AddHeader("authorization", "Basic " + Convert.ToBase64String(ua));
string[] crumbSplit = JenkinCrumb.Split(':');
restRequest.AddHeader(crumbSplit[0], crumbSplit[1]);
restRequest.AddParameter("text/xml", JobConfig.InnerXml, ParameterType.RequestBody);
IRestResponse restResponse = restClient.Execute(restRequest);
string resp = restResponse.Content;
}

curl -v -X POST https://jenkinsurl.fr:8443/job/jobname/config.xml --data-binary "#config.xml" -u "jenkinsusername:yourjenkinstoken" -H "Content-Type: application/xml"

Related

UPS API OAuth token request fails

In the UPS developer portal, I have created an application that has a Client Id and a Client Secret. Next, I want to obtain an OAuth token so I can use it to access their other APIs. I am creating my token request as per the spec and I am receiving the following error:
{"response":{"errors":[{"code":"10400","message":"Invalid/Missing Authorization Header"}]}}
The spec has a "try it out" feature where you can obtain a test token. It prompts the user to fill in a x-merchant-id parameter and a grant_type form variable and creates a curl request that looks like this:
curl -X POST "https://wwwcie.ups.com/security/v1/oauth/token"
-H "accept: application/json"
-H "x-merchant-id: {My_Client_Id_Goes_Here}"
-H "Content-Type: application/x-www-form-urlencoded"
-d "grant_type=client_credentials"
For x-merchant_id, I have used my app’s Client Id. It is not clear if the value for grant_type should be the phrase client_credentials (the page makes it seem like this is the only valid value) or my app’s actual Client Secret. I have tried both and get the same error each time.
There are a million examples out there on how to use their (old style) API keys, but practically nothing about how to obtain an OAuth token except for the instructions linked above!
Your curl looks good to me, just missing the Authorization header which is a base64(id:secret)
curl -X POST "https://wwwcie.ups.com/security/v1/oauth/token"
-H "Authorization: Basic {id}:{secret}"
-H "accept: application/json"
-H "x-merchant-id: {My_Client_Id_Goes_Here}"
-H "Content-Type: application/x-www-form-urlencoded"
-d "grant_type=client_credentials"
If you're using the 'Try out' feature, select the Authorize button at the top and enter the client id and secret, that's where its used to set the Authorization header. One thing to note, the 'Try out' feature only work with the Test product(s) assigned to your app
Additional info
UPS have 2 environments
Testing: wwwcie.ups.com
Production: onlinetools.ups.com
Testing env only accepts Test Products, so note the product(s) that was added to your app
I was stuck with this issue for a long time.
Your comments did eventually help me. But I wanted to make it more clear for someone else reading this later....
Instead of using UPS username and password in the authorization header. You need to encode the clientId and secret with a colon between and send that.
For PHP:
$clientID = base64_encode("{clientID}:{clientSecret}");
$headers = array();
$headers[] = "Authorization: Basic $clientID";
$headers[] = 'Accept: application/json';
$headers[] = "X-Merchant-Id: {clientID}";
$headers[] = 'Content-Type: application/x-www-form-urlencoded';
One more addition to the other answers: make sure you add the "OAuth" product to your UPS app. I had added "tracking" and "tracking test", but not OAuth. I was getting the "{"code":"10401","message":"ClientId is Invalid"}" response when I tried to get a token, even though I was sure I had everything else right.
Adding OAuth to my UPS app presumably added my ClientID to their OAuth system, and my token requests started working.
Just in case somebody with .NET/C# background will be looking for the similar topic - an UPS RESTFul API authorization and tracking info processing solution here is the one working well for me using proposed here approach:
#define TEST_MODE
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
var myClientID = "{Type your ClientId here}";
var mySecretID = "{Type your SecretID here}";
#if TEST_MODE
var baseAddress = "https://wwwcie.ups.com"; // testing
#else
var baseAddress = "https://onlinetools.ups.com"; // production
#endif
var accessID = $"{myClientID}:{mySecretID}";
var base64AccessID = Convert.ToBase64String(Encoding.ASCII.GetBytes(accessID));
using (var client = new HttpClient())
{
// Get Access Token
var request = new HttpRequestMessage()
{
Method = HttpMethod.Post,
RequestUri = new Uri($"{baseAddress}/security/v1/oauth/token"),
Content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "client_credentials")
})
};
request.Headers.Add("Authorization", $"Basic {base64AccessID}");
var response = await client.SendAsync(request);
var jsonResult = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<JsonObject>(jsonResult);
var access_token = result?["access_token"]?.ToString();
// Get Tracking Info
var trackingNumber = "1Z5338FF0107231059"; // provided by UPS for testing
request = new HttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri($"{baseAddress}/api/track/v1/details/{trackingNumber}")
};
request.Headers.Add("Authorization", $"Bearer {access_token}");
request.Headers.Add("transId", $"{DateTime.Now.Ticks}");
#if TEST_MODE
request.Headers.Add("transactionSrc", $"testing");
#else
request.Headers.Add("transactionSrc", $"{App Name and version}");
#endif
response = await client.SendAsync(request);
jsonResult = await response.Content.ReadAsStringAsync();
Console.WriteLine(jsonResult);
}

Get SQL results from DB2 on cloud to Power Query via API

I try to connect to db2 on cloud via Excel Power Query.
Based on documentation this is format of curl request:
curl -X POST https://hostname.com/dbapi/v4/sql_query_export -H 'authorization: Bearer MyToken' -H 'content-type: text/csv' -d '{"command":"select * from mytable"}'
I tried to go via GUI but this gives me error
I am pretty sure I am not doing it right, but I could not even google how to pass my parameters.
Could someone please navigate how to assembly M code for this?
I tried this according to #nfgl answer
let
body = [#"command"="select * from mytable"]
,json = Json.FromValue(body)
,wc = Web.Contents("https://hostname.com/dbapi/v4/sql_query_export", [Headers=[#"content-type"="text/csv", authorization="Bearer XXX"]])
,Source = Csv.Document(wc,[Delimiter=",", Encoding=65001, QuoteStyle=QuoteStyle.Csv])
in
Source
However cannot go around credentials ui anonymously:
When I try Web API with token:
BTW, everything works with python:
import http.client
conn = http.client.HTTPSConnection("hostname.com")
payload = "{\"command\":\"select * from mytable\"}"
headers = {
'content-type': "text/csv",
'authorization': "Bearer XXX"
}
conn.request("POST", "/dbapi/v4/sql_query_export", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
You can't do it via GUI, command JSON must be in request content, and content-type is the one you send, ie JSON, open advanced editor and do something like this
let
url = "https://showcase.api.linx.twenty57.net/UnixTime/fromunixtimestamp",
body = [#"UnixTimeStamp"= 1589772280, #"Timezone"=""],
json = Json.FromValue(body),
wc = Web.Contents(url, [Headers=[#"Content-Type"="application/json"], Content=json]),
Source = Csv.Document(wc,[Delimiter=",", Encoding=65001, QuoteStyle=QuoteStyle.Csv])
in
Source

Gnome Shell Extension: Send Request with Authorization Bearer Headers

I am trying to build a gnome shell extension (using gjs) that I need to communicate with an external REST API. In order to do so, I need to accompany my requests with the header: Authorization: Bearer <token> and with a Content-Type: application/json.
I have looked all over for questions like this and I did find some similar ones but none of them works. The documentation is not helpful at all, and, if anything, it has only confused me more.
With curl I could send that request as follows:
curl -X GET -H "Authorization: Bearer <token>" -H "Content-Type: application/json" <url>
So far, I have only created extensions that send simple GET requests with no headers. Then I would do the following:
const Soup = imports.gi.Soup;
let soupSyncSession = new Soup.SessionSync();
let message = Soup.Message.new('GET', url);
let responseCode = soupSyncSession.send_message(message);
let res;
if(responseCode == 200) {
res = JSON.parse(message['response-body'].data);
}
Any idea on how I can add the headers? Any help would be appreciated!
EDIT:
By using #ptomato's answer I ended up using the following code:
function send_request(url, type='GET') {
let message = Soup.Message.new(type, url);
message.request_headers.append(
'Authorization',
`Bearer ${token}`
)
message.request_headers.set_content_type("application/json", null);
let responseCode = soupSyncSession.send_message(message);
let out;
if(responseCode == 200) {
try {
out = JSON.parse(message['response-body'].data);
} catch(error) {
log(error);
}
}
return out;
}
Initial Comment:
So, I managed to find a workaround but it is not efficient and so I will not mark it as the accepted answer. If anyone knows how to answer my question using Soup, please answer!
My workaround involves using the imports.misc.util file which includes the function spawnCommandLine for executing shell commands. So, I used curl in order to download the json to a file (the path variable below):
Util.spawnCommandLine(`/usr/bin/curl -X ${type} -H "Authorization: Bearer ${token}" -H "Content-Type: application/json" ${url} -o ${path}`);
and then I read the contents by using the following:
let text = GLib.file_get_contents(path)[1];
let json_result = JSON.parse(text);
This is not efficient at all and there should be an easier way around. But, until that is found, I hope this will be able to help someone else.
message.request_headers is a Soup.MessageHeaders object to which you can append() the authorization and content type headers.
Additionally there is a convenient set_content_type() method for the content type header specifically.

ERROR: The remote server returned an error: (400) Bad Request

I am using aspx vb .net to connect with instagram api
I am using the following link as references: https://code.msdn.microsoft.com/Haroon-Said-e1d8d388
ERROR: The remote server returned an error: (400) Bad Request.
It is weird becuase i followed all steps and imported json as showed in above link. any idea? below is my code:
Dim json As String = ""
Try
Dim parameters As New NameValueCollection
parameters.Add("client_id", Client_ID)
parameters.Add("client_secret", ClientSecret)
parameters.Add("grant_type", "authorization_code")
parameters.Add("redirect_uri", Redirect_URI)
parameters.Add("code", Code)
Dim client As WebClient = New WebClient()
Try
'ERROR HERE
Dim result = client.UploadValues("https://api.instagram.com/oauth/access_token", "POST", parameters)
...
Catch ex As Exception
labelTest.Text += "---" & ex.Message
End Try
Thanks. yeah I been working on this for couple months now and trying to debug but I just have no idea whats going on. I mean I looked at insta api webbsite sill no luck. I tested my values also and they seem to be correct:
curl -F 'client_id=CLIENT_ID' \
-F 'client_secret=CLIENT_SECRET' \
-F 'grant_type=authorization_code' \
-F 'redirect_uri=AUTHORIZATION_REDIRECT_URI' \
-F 'code=CODE' \
https://api.instagram.com/oauth/access_token
client_secret = f208d9fc9cec4b69bdd5f8f1386a
client_secret = d836619eede4490fd12983b95961
grant_type = authorization_code
redirect_uri = http://localhost:1861/UI/Home.aspx
code = 6185508825da0c28a33ac5dcc77
note, 'code' i am getting when when user logs into insta. I used the following url to get the code:
https://api.instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=REDIRECT-URI&response_type=code
I know authorize is correct becuase it gives me code in url
solved!
just changed response_type from code to token... it will give you access_token

Binance API Keys

I have set up a read-only API key on Binance to access account information like currency balances but I can't see the JSON data. The string query I put into the URL returns the following error:
{"code":-2014,"msg":"API-key format invalid."}
The URL I am using is this: https://api.binance.com/api/v3/account?X-MBX-APIKEY=**key**&signature=**s-key**
The documentation for Binance API can be found here: https://www.binance.com/restapipub.html. What am I doing wrong ?
Binance's websocket API kinda tricky to use. Also there is no way to use a secret key.
Common usage
Send HTTP POST request with your secret API key as a X-MBX-APIKEY header to https://api.binance.com/api/v1/userDataStream
You will get listen key which should be used for websocket connection. It will be available 1 hour.
{"listenKey": "your listen key here"}
Use it when connecting to Binance's websocket
wss://stream.binance.com:9443/ws/{your listen key here}
Python example
import ssl
from websocket import create_connection
import requests
KEY = 'your-secret-key'
url = 'https://api.binance.com/api/v1/userDataStream'
listen_key = requests.post(url, headers={'X-MBX-APIKEY': KEY})['listenKey']
connection = create_connection('wss://stream.binance.com:9443/ws/{}'.format(KEY),
sslopt={'cert_reqs': ssl.CERT_NONE})
def get_listen_key_by_REST(binance_api_key):
url = 'https://api.binance.com/api/v1/userDataStream'
response = requests.post(url, headers={'X-MBX-APIKEY': binance_api_key}) # ['listenKey']
json = response.json()
return json['listenKey']
print(get_listen_key_by_REST(binance_api_key))
def get_all_orders(symbol, binance_api_key, binance_secret_key):
"""Get all account orders; active, canceled, or filled.
Args: symbol: Symbol name, e.g. `BTCUSDT`.
Returns:
"""
from datetime import datetime, timezone, timedelta
now = datetime.now(timezone.utc)
epoch = datetime(1970, 1, 1, tzinfo=timezone.utc) # use POSIX epoch
posix_timestamp_micros = (now - epoch) // timedelta(microseconds=1)
posix_timestamp_millis = posix_timestamp_micros // 1000 # or `/ 1e3` for float
import hmac, hashlib
queryString = "symbol=" + symbol + "&timestamp=" + str(
posix_timestamp_millis)
signature = hmac.new(binance_secret_key.encode(), queryString.encode(), hashlib.sha256).hexdigest()
url = "https://api.binance.com/api/v3/allOrders"
url = url + f"?{queryString}&signature={signature}"
response = requests.get(url, headers={'X-MBX-APIKEY': binance_api_key})
return response.json()
You put it in the header. Following is tested working PHP example borrowed from jaggedsoft binance PHP library, it's a signed request that will return the account status.
$api_key = "cool_key";
$secret = "awesome_secret";
$opt = [
"http" => [
"method" => "GET",
"header" => "User-Agent: Mozilla/4.0 (compatible; PHP Binance API)\r\nX-MBX-APIKEY: {$api_key}\r\n"
]
];
$context = stream_context_create($opt);
$params['timestamp'] = number_format(microtime(true)*1000,0,'.','');
$query = http_build_query($params, '', '&');
$signature = hash_hmac('sha256', $query, $secret);
$endpoint = "https://api.binance.com/wapi/v3/accountStatus.html?{$query}&signature={$signature}";
$res = json_decode(file_get_contents($endpoint, false, $context), true);
X-MBX-APIKEY should be set as a field in the HTTP header, and not as a HTTP parameter. See this page for more information on HTTP header fields.
However, I tried the same with Excel and could not get it running until now.
Another open question is how to use the secret key.
This worked for me:
base_url="https://api.binance.com"
account_info="/api/v3/account"
url="${base_url}${account_info}"
apikey="your_apikey"
secret="your_secret"
queryString="timestamp=$(date +%s)" #$(python3 binance_time.py) must sync
requestBody=""
signature="$(echo -n "${queryString}${requestBody}" | openssl dgst -sha256 -hmac $secret)"
signature="$(echo $signature | cut -f2 -d" ")"
req=$(curl -H "X-MBX-APIKEY: $apikey" -X GET "$url?$queryString&signature=$signature")
echo $req
You should set the API key in the request header, not as a parameter in the request url. Please provide more information on your request procedure (language, etc.).
If you are based in USA - make sure to switch your base url to https://api.binance.us
_httpClient.DefaultRequestHeaders.Add("X-MBX-APIKEY", "apikey");
_httpClient.DefaultRequestHeaders.Add("SecretKey", "secretkey");
curl -H "X-MBX-APIKEY:your_api_key" -X POST https://api.binance.com/api/v1/userDataStream