I am trying to create a pool using RESTful API. I know there is C# library for batch service, but in order to programmingly specify the subnet id, I have to use RESTful API to create it which I read about in this MSDN article.
My Post URI follow the format
https://{account-name}.{region-id}.batch.azure.com/pools?api-version={api-version}
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/json";
client.Headers[HttpRequestHeader.Authorization] = "SharedKey <AccountName>:<Signature>";
client.Headers[HttpRequestHeader.Date] = DateTime.UtcNow.ToString();
try
{
result = client.UploadString(baseURI, "POST", json);
}
catch(Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
Console.WriteLine(result);
}
The json I sent: {"Id":"DotNetPool","vmSize":"small"}
at System.Net.WebClient.UploadDataInternal(Uri address, String method, Byte[] data, WebRequest& request) at System.Net.WebClient.UploadString(Uri address, String method, String data)
at System.Net.WebClient.UploadString(String address, String method, String data) at batchServer.Program.createPool(String poolId, String machineSize, String osFamily, String subnetId, String commandLine, Int32 numberOfMachine, List`1 resourceFiles) in C:\Users\fange\Downloads\ALMTest-master\batchServer\Program.cs:line 61
Can anyone help me out?
Based on the code you provided, I tested on my side and reproduced this issue. When you debug the code, you could find the detailed error as follows:
As far as I know, some common headers are considered restricted and are protected by the system and cannot be set or changed in a WebHeaderCollection
object, you could follow this tutorial.
For a simple way, I recommend that you could use HttpWebRequest
instead of WebClient
to achieve your purpose. Here is my testing code for you to create a pool using RESTful API.
public static void CreatePoolViaRestAPI(string baseUrl, string batchAccountName, string batchAccountKey,string jsonData)
{
string verb = "POST";
string apiVersion= "2016-07-01.3.1";
string ocpDate= DateTime.UtcNow.ToString("R");
string contentType = "application/json; odata=minimalmetadata; charset=utf-8";
string reqUrl = string.Format("{0}/pools?api-version={1}", baseUrl, apiVersion);
//construct the request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(reqUrl);
request.Method = verb;
//Set ContentType
request.ContentType = contentType;
//Set ocp-date
request.Headers.Add("ocp-date", ocpDate);
var buffer = Encoding.UTF8.GetBytes(jsonData);
request.ContentLength = buffer.Length;
#region generate the signature
string CanonicalizedHeaders = string.Format("ocp-date:{0}", ocpDate);
string CanonicalizedResource = string.Format("/{0}/pools\napi-version:{1}", batchAccountName, apiVersion);
string stringToSign = string.Format("{0}\n\n\n{1}\n\n{2}\n\n\n\n\n\n\n{3}\n{4}",
verb,
buffer.Length,
contentType,
CanonicalizedHeaders, CanonicalizedResource);
//encode the stringToSign
string signature = EncodeSignStringForSharedKey(stringToSign, batchAccountKey);
#endregion
//Set Authorization header
request.Headers.Add("Authorization", string.Format("SharedKey {0}:{1}", batchAccountName, signature));
using (var rs = request.GetRequestStream())
{
rs.Write(buffer, 0, buffer.Length);
}
//send the request and get response
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
Console.WriteLine("Response status code:{0}", response.StatusCode);
}
}
Note: The cloudServiceConfiguration and virtualMachineConfiguration properties are mutually exclusive and only one of the properties can be specified. If neither is specified then the Batch service returns Bad Request (400). Therefore, the jsonData parameter in the function above should look like as follows:
"{\"id\":\"DotNetPool\",\"vmSize\":\"small\",\"cloudServiceConfiguration\":{\"osFamily\":\"4\"}}"
UPDATE:
The method for encoding stringToSign would look like as follows:
public string EncodeSignStringForSharedKey(string stringToSign, string accountKey)
{
HMACSHA256 h = new HMACSHA256(Convert.FromBase64String(accountKey));
var byteArray = h.ComputeHash(Encoding.UTF8.GetBytes(stringToSign));
string signature = Convert.ToBase64String(byteArray);
return signature;
}
Details you could follow Authentication via Shared Key.