简体   繁体   中英

Create azure batch pool using Azure Batch Restful API, encounter exception

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}

Code

 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 .

The Azure Batch C# Client SDK as of 5.0.0 has the capability of joining a Virtual Network for Windows Cloud Service-based instances. You do not need to directly call the REST Endpoint.

- Added support for joining a CloudPool to a virtual network on using the NetworkConfiguration property.

You can view the ChangeLog for 5.0.0 here: https://www.nuget.org/packages/Azure.Batch/5.0.0 but please use the latest version.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM