Example #1
0
        public RequestResponse SendRequest()
        {
            /*
             * for the purposes of this demo, many Nutanix clusters will still use self-signed certificates
             * if SSL errors are not ignored, connections will be refused since we aren't automatically accepting self-signed certs in this app
             */

            ServicePointManager.ServerCertificateValidationCallback = ((sender, certificate, chain, sslPolicyErrors) => true);
            ServicePointManager.Expect100Continue = true;
            ServicePointManager.SecurityProtocol  = SecurityProtocolType.Tls12;

            RequestResponse Response     = new RequestResponse();
            HttpWebResponse HttpResponse = null;

            try
            {
                var request = (HttpWebRequest)WebRequest.Create(Parameters.URI);
                request.Method = Parameters.Method;

                /*
                 * this section only applies if the user as selected to send a POST request
                 * if the POST method is selected, we also need to process and send the POST body
                 */
                if (Parameters.Method != "GET")
                {
                    var requestBody = Encoding.ASCII.GetBytes(Parameters.Payload);
                    var newStream   = request.GetRequestStream();
                    newStream.Write(requestBody, 0, requestBody.Length);
                    newStream.Close();
                }

                /*
                 * setup the request headers
                 *
                 * for this app, we are only worried about the authentication type (Basic)
                 * and the valid encoding (application/json for Nutanix clusters)
                 */
                String authHeader = System.Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(Parameters.Username + ":" + Parameters.Password));
                request.Headers.Add("Authorization", "Basic " + authHeader);
                request.Headers.Add("Accept-Encoding", "application/json");
                request.ContentType = "application/json";
                request.Accept      = "application/json";

                /*
                 * make sure the request doesn't sit there forever ...
                 * set this to a more appropriate value if accessing API URIs over slow/high-latency connections (e.g. VPN)
                 */
                request.Timeout = 5000;

                HttpResponse = (HttpWebResponse)request.GetResponse();
                using (Stream HttpResponseStream = HttpResponse.GetResponseStream())
                {
                    if (HttpResponseStream != null)
                    {
                        using (StreamReader reader = new StreamReader(HttpResponseStream))
                        {
                            Response.Code    = 1;
                            Response.Message = reader.ReadToEnd();
                        }
                    }
                }
            }
            catch (System.Net.WebException ex)
            {
                /**
                 * network error, request properties, auth errors
                 */
                Response.Code    = 99;
                Response.Message = "An error occurred while making the request (e.g. network, request properties, authentication).";
                Response.Details = "{\"errors\":[\"" + ex.Message.ToString() + "\"]}";
            }
            catch (System.Net.ProtocolViolationException ex)
            {
                /**
                 * payload error, e.g. malformed JSON body
                 */
                Response.Code    = 99;
                Response.Message = "A payload/request body error occurred while making the request.";
                Response.Details = "{\"errors\":[\"" + ex.Message.ToString() + "\"]}";
            }
            catch (Exception ex)
            {
                /**
                 * don't catch generic "Exception" in production ...
                 */
                Response.Code    = 99;
                Response.Message = "An unhandled exception occurred while making the request.";
                Response.Details = "{\"errors\":[\"" + ex.Message.ToString() + "\"]}";
            }
            finally
            {
                if (HttpResponse != null)
                {
                    ((IDisposable)HttpResponse).Dispose();
                }
            }

            return(Response);
        }
Example #2
0
        static void Main(string[] args)
        {
            /**
             * hard-coded password here - you'd need to do this properly in production
             */
            string ClusterUsername = "******";
            string ClusterPassword = "******";
            string ClusterIp       = "10.0.0.1";

            /**
             * instance of our RequestParameters class
             * done this way purely to nicely package the request parameters__
             *
             * important note - the current v3 API will return a MAXIMUM of 500 VMs for any single request,
             * regardless of the value specified for "length"
             *
             * to collect a list of all VMs on systems with >500 VMs, please use a
             * combination of the 'length' and 'offset' parameters.
             *
             * for example, {"kind":"vm","length":500,"offset":501} on a cluster with
             * 517 VMs would return a list of 15 VMs i.e. VMs from 501-516, excluding CVM
             */
            RequestParameters Parameters = new RequestParameters()
            {
                URI      = "https://" + ClusterIp + ":9440/api/nutanix/v3/vms/list",
                Username = ClusterUsername,
                Password = ClusterPassword,
                Payload  = "{\"kind\":\"vm\",\"length\":500}",
                Method   = "POST"
            };

            RESTClient Client = new RESTClient(Parameters);

            HttpWebResponse HttpResponse = null;

            /**
             * first we'll send a request that we can use to find out how many VMs are
             * in this cluster
             * if the number of VMs on the cluster is >500, we'll run additional requests
             * later to handle them in groups of <=500
             */

            /**
             * the RESTClient.SendRequest method contains basic exception handling
             * you should modify this to avoid catching generic exceptions,
             * if you plan to use any of this in your own apps
             *
             * this note is here for those wondering why there's no try/catch handling
             * around the send request action below
             */

            RequestResponse CountVmRequest = new RequestResponse();

            /**
             * send the request
             */
            CountVmRequest = Client.SendRequest();

            /**
             * process the response
             * at this time we're just counting the VMs and, based on the number of VMs
             * in the cluster, will either show them all or make subsequent requests to
             * get the remaining VMs
             */

            /**
             * if the response code isn't 1, something went wrong
             * in this basic demo, 1 is successful, 99 is failure
             * these custom codes are returned from the RESTClient.SendRequest() method
             * we are also handling exceptions in the RESTClient.SendRequest() - please see
             * that method for details on how exceptions are handled
             */
            if (CountVmRequest.Code == 99)
            {
                Console.WriteLine("Error code 99 indicates the API request either failed or returned an invalid/unexpected response.  Additional information follows.\n");
                Console.WriteLine(CountVmRequest.Message);
                Console.WriteLine(CountVmRequest.Details);
            }
            else
            {
                var     JsonSerializer = new JavaScriptSerializer();
                dynamic JsonObject     = JsonSerializer.Deserialize <dynamic>(CountVmRequest.Message);

                /**
                 * grab the number of VMs from this initial request
                 * we'll use this number to calculate how many interations
                 * to make in upcoming requests
                 */
                int VmCount = Convert.ToInt16(JsonObject["metadata"]["total_matches"]);
                Console.WriteLine("Total VMs in this cluster: " + VmCount);
                Console.WriteLine("Total VMs in this request (iteration #0): " + Convert.ToInt16(JsonObject["metadata"]["length"]));

                /**
                 * the nutanix "vms" API will only ever return 500 VMs
                 * this will apply even if the "length" parameter is set to a value >500
                 */
                if (VmCount >= 500)
                {
                    /**
                     * at this point you would "do something" based on knowing there are
                     * >500 VMs in the cluster
                     *
                     * for example, you could iterate over the VMs, collecting the necessary information, etc
                     *
                     * for our demo, we've already got a response containing
                     * information about the first 500 VMs so there's no need
                     * to submit a request for the first 500 again (expensive and unnecessary)
                     */
                    Console.WriteLine("There are more than 500 VMs in this cluster.");
                    Console.WriteLine("Multiple iterations/requests are required to collect all VM information.");

                    /**
                     * by immediately setting the offset to 500, subsequent requests
                     * will start from VM at index 501 and go forward from there
                     * again, we've already got the response above for the first 500 VMs
                     *
                     * we're using chunks of 500 VMs here, but in a real app there's no
                     * reason why this chunk needs to be 500
                     * note, however, the 500 is the MAXIMUM number of VMs returned in a
                     * single request
                     */
                    int MaxVmsInResponse = 500;
                    int Offset           = MaxVmsInResponse;

                    /**
                     * work out how many interations are required
                     * simple math based on the number of times a 500 VM response will be received
                     */
                    int Iterations = VmCount / MaxVmsInResponse;
                    Console.WriteLine("Total iterations required, including the initial request: " + (Iterations + 1));

                    /**
                     * starting at 1 here because we've already completed iteration "0"
                     */
                    for (int Iterator = 1; Iterator <= Iterations; Iterator++)
                    {
                        RequestParameters IterationParameters = new RequestParameters()
                        {
                            URI      = "https://" + ClusterIp + ":9440/api/nutanix/v3/vms/list",
                            Username = ClusterUsername,
                            Password = ClusterPassword,
                            Payload  = "{\"kind\":\"vm\",\"length\":500,\"offset\":" + Offset + "}",
                            Method   = "POST"
                        };

                        /**
                         * reuse the previous RESTClient instance
                         */
                        Client.Parameters = IterationParameters;
                        RequestResponse IterationRequest = Client.SendRequest();

                        dynamic IterationJsonObject = JsonSerializer.Deserialize <dynamic>(IterationRequest.Message);
                        int     IterationVmCount    = Convert.ToInt16(IterationJsonObject["metadata"]["length"]);
                        Console.WriteLine("Total VMs in this request (iteration #" + Iterator + "): " + IterationVmCount);
                        Offset = Offset + MaxVmsInResponse;
                    }
                }
                else
                {
                    /**
                     * at this point you would "do something" based on there being
                     * <500 VMs in the cluster
                     *
                     * iterate over the VMs, collecting the necessary informatin, etc
                     */
                    Console.WriteLine("There are fewer than 500 VMs in this cluster.");
                    Console.WriteLine("Only a single iteration/request is required to collect all VM information.");

                    /**
                     * do something useful here
                     * this isn't an unintentional comment - it's where you'd do something useful  :)
                     */
                }
            }

            /**
             * make sure we clean up after ourselves
             */
            if (HttpResponse != null)
            {
                ((IDisposable)HttpResponse).Dispose();
            }

            /**
             * wait for the user to press a key
             * this is only here because there's an assumption/guess that, initially at least,
             * this small demo app will be run inside Visual Studio
             */
            Console.WriteLine("\nPress any key to exit.");
            Console.ReadKey();
        }