Wednesday, July 25, 2012

Create a Persistent VM using Windows Azure Service Management REST APIs

Here I’m posting on how we can create a Persistent VM using REST APIs using the basic HTTPRequest POST methods.
First we need to know where we need to POST our request. The URL will be:
You have to replace your Azure subscription id and the service on which this VM will be hosted.
Next step is what we need to post in our request. So we’ll create our request body. It is an XML file which will have some of the properties related to the service which we want to host.
So I’ll call my xml file as CreateVM.xml and it will be like:
<Deployment xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
   <Name>deployment-name</Name>
   <Label>deployment-label</Label>  
   <RoleList>
      <Role>
         <RoleName>name-of-the-vm</RoleName>
         <RoleType>PersistentVMRole</RoleType>     
         <ConfigurationSets>
            <ConfigurationSet>
                <!—Include either a WindowsProvisioningConfigurationSet or a LinuxProvisioningConfigurationSet, but not both -->                <ConfigurationSetType>WindowsProvisioningConfiguration<ConfigurationSetType>                <ComputerName>computer-name</ComputerName>                <AdminPassword>administrator-password-for-the-vm</AdminPassword>                 <ResetPasswordOnFirstLogon>true|false</ResetPasswordOnFirstLogon>                <EnableAutomaticUpdate>true|false</EnableAutomationUpdate>                  <TimeZone>Pacific Standard Time</TimeZone>
                <DomainJoin>
                   <Credentials>
                        <Domain>domain-to-join</Domain>
                        <Username>user-name-in-the-domain</Username>
                        <Password>password-for-the-user-name</Password>
                   </Credentials>
                   <JoinDomain>domain-to-join</JoinDomain>
                   <MachineObjectOU>distinguished-name-of-the-ou<MachineObjectOU>
                </DomainJoin>
                <StoredCertificateSettings>
                   <CertificateSetting>
                        <StoreLocation>LocalMachine</StoreLocation>
                        <StoreName>name-of-store-on-the-machine</StoreName>
                        <Thumbprint>certificate-thumbprint</Thumbprint>
                   </CertificateSetting>
                </StoredCertificateSettings>
            </ConfigurationSet>
            <!—Include either a WindowsProvisioningConfigurationSet or a LinuxProvisioningConfigurationSet, but not both -->
            <ConfigurationSet>                <ConfigurationSetType>LinuxProvisioningConfiguration<ConfigurationSetType>
                <HostName>host-name-for-the-vm</HostName>
                <UserName>new-user-name</UserName>
                <UserPassword>password-for-the-new-user</UserPassword>
                <DisableSshPasswordAuthentication>true|false</DisableSshPasswordAuthentication>      
                <SSH>
                    <PublicKeys>
                       <PublicKey>
                           <FingerPrint>certificate-fingerprint</FingerPrint>
                           <Path>SSH-public-key-storage-location</Path>  
                       </PublicKey>
                    </PublicKeys>
                    <KeyPairs>
                       <KeyPair>
                           <FingerPrint>certificate-fingerprint</FinguerPrint>
                           <Path>SSH-public-key-storage-location</Path>
                       </KeyPair>
                    </KeyPairs>
                </SSH>
            </ConfigurationSet>    
            <ConfigurationSet>
                <ConfigurationSetType>NetworkConfiguration<ConfigurationSetType>
                <InputEndpoints>
                    <InputEndpoint>
                        <EnableDirectServerReturn>true|false</EnableDirectServerReturn>             
                        <LoadBalancedEndpointSetName></LoadBalancedEndpointSetName>
                        <LocalPort>local-port-number</LocalPort>
                        <Name>endpoint-name</Name>
                        <Port>external-port-number</Port>
                        <LoadBalancerProbe>
                            <Path>relative-path-that-contains-status</Path>
                            <Port>port-to-use-for-status</Port>
                            <Protocol>TCP|UDP</Protocol>
                        </LoadBalancerProbe>
                        <Protocol>TCP|UDP</Protocol>                 
                    </InputEndpoint>
                </InputEndpoints>
                <SubnetNames>
                 <string>FrontEndSubnet1</string>
                 <string>BackEndSubnet1</string>
                </SubnetNames>       
            </ConfigurationSet>
         </ConfigurationSets>
         <AvailabilitySetName>availability-set-for-the-vm</AvailabilitySetName>
         <DataVirtualHardDisks>
            <DataVirtualHardDisk>
               <HostCaching>ReadOnly|ReadWrite</HostCaching>
               <DiskLabel>data-disk-label</DiskLabel>         
               <DiskName>new-or-existing-disk-name</DiskName>
               <Lun>logical-unit-number</Lun>
               <LogicalDiskSizeInGB>size-in-gb-of-the-data-data-disk</LogicalDiskSizeInGB>           
               <MediaLink>url-of-the-blob-containing-the-data-disk</MediaLink>
            </DataVirtualHardDisk>
         </DataVirtualHardDisks>
         <OSVirtualHardDisk>
            <HostCaching>ReadOnly|ReadWrite</HostCaching>  
            <DiskLabel>os-disk-label</DiskLabel>
            <DiskName>new-or-existing-disk-name</DiskName>               
            <MediaLink>url-of-the-blob-containing-the-os-disk</MediaLink>
            <SourceImageName>name-of-the-image-to-use-for-disk-creation</SourceImageName>
         </OSVirtualHardDisk>     
         <RoleSize>ExtraSmall|Small|Medium|Large|ExtraLarge</RoleSize>     
      </Role>
    </RoleList>
    <VirtualNetworkName>MyProdictionNetwork</VirtualNetworkName>
    <Dns>
        <DnsServers>
            <DnsServer>
                <Name>dns-name</Name>
                <Address>dns-ip-address</Address>
            </DnsServer>
            <DnsServer>
                <Name>dns-name</Name>
                <Address>dns-ip-address</Address>
            </DnsServer>
        </DnsServers>
    </Dns>
</Deployment>
Now we will have to use this XML in our C# code to POST the request to the URL specified above.
I’ll write a function called CreatedVM which will accept parameters like URL, SubscriptionId, HostedServiceName and the location of XML file which needs to be posted.
private void CreateVM(string url, string subscriptionId, string xmlLocationPath, string hostedServiceName)
{
                Uri uri = new Uri(String.Format(url, hostedServiceName, subscriptionId));
                XDocument document = null;
                HttpWebRequest request =

HttpWebRequest)HttpWebRequest.Create(uri.ToString());
request.Timeout = 50000;
request.Headers.Add("x-ms-version", “2012-03-01”);
request.ClientCertificates.Add(certificate);
request.ContentType = "application/xml";
                If(xmlLocationPath != null || !string.IsNullorEmpty(xmlLocationPath)
                {
                                document =       XDocument.Load(xmlLocationPath);
              request.Method = "POST";
              StreamWriter writer = newStreamWriter(request.GetRequestStream());
              writer.Write(document);
writer.Close();
       }
                HttpStatusCode statusCode;
HttpWebResponse response;
try
{
       response = (HttpWebResponse)request.GetResponse();
}
catch (WebExceptionex)
{
// GetResponse throws a WebException for 400 and 500 status codes
response = (HttpWebResponse)ex.Response;
}
statusCode = response.StatusCode;
       response.Close();     
}
We can customize this method. I’ve written a very basic example to explain this.
Please note that you should have a valid X509 certificate in your cert store as well a matching certificate uploaded on Azure portal for your subscription ID. You can retrieve the certificate using the thumbprint of the certificate.
The XML mentioned above is for MS Version “2012-03-01”.
For more detailed explanation of the properties specified in XML, please refer to:
Cheers
Ankit

1 comment:

  1. Hi Ankit, thanks for your valuable input, after trying the above code for WindowsProvisioningConfigurationSet, i am getting error as (400)Bad Request. I guess my request body is somewhere going wrong but could not find the exact location.
    Request you to help me out, as i am succesfully geting response for GET requests.

    ReplyDelete