├── .disclaimer ├── .gitignore ├── LICENSE ├── NOTICE ├── _config.yml ├── blueprints ├── basic_linux_vm.json ├── centos8_docker_flask │ ├── .disclaimer │ ├── README.md │ ├── centos8_docker_flask.json │ └── images │ │ ├── screenshot.png │ │ └── service_ip_address.png ├── create_lcm_darksite_web_server.json └── scaling_demo_october_2019.json ├── csharp ├── app_running.png ├── app_running_large.png ├── configure_console_app.png ├── list_vm_v3 │ ├── list_vm_v3.cs │ └── readme.rst ├── list_vm_v3_large │ ├── list_vm_v3_large.cs │ └── readme.rst ├── new_console_app.png ├── new_project.png └── readme.rst ├── docs └── index.md ├── go ├── batch_requests │ ├── batch_requests │ ├── batch_requests.go │ ├── batch_requests.json │ ├── readme.rst │ └── screenshot.png ├── multiple_vm_clone │ ├── multiple_vm_clone.go │ ├── multiple_vm_clone.png │ └── readme.rst ├── readme.rst └── v4api_sdk │ ├── .gitignore │ ├── README.md │ ├── list_images_sdk.go │ └── screenshot.png ├── js └── v4api_sdk │ ├── .gitignore │ ├── README.md │ ├── config-example.json │ ├── list_clusters_sdk.js │ ├── package.json │ └── screenshot.png ├── postman ├── Nutanix REST API Testing.postman_collection.json └── nutanix_api_v3_runbooks_endpoints.json ├── powershell ├── batch_request_simple │ ├── batch_request_simple.ps1 │ ├── readme.rst │ └── script_output.png ├── check_ps_version.png ├── create_vm_v3_basic │ ├── create_vm_v3_basic.ps1 │ ├── readme.rst │ └── script_output.png ├── readme.rst └── script_output.png ├── python ├── README.md ├── batch_request_simple │ ├── .gitignore │ ├── batch_request_simple.json │ ├── batch_request_simple.json.sample │ ├── batch_request_simple.py │ └── readme.rst ├── create_image_v2.0 │ ├── create_image_v2.0.json │ ├── create_image_v2.0.py │ ├── readme.rst │ ├── screenshot.png │ └── setup.py ├── create_vm_v3_basic │ ├── create_vm_v3_basic.json │ ├── create_vm_v3_basic.py │ ├── readme.rst │ ├── screenshot.png │ └── setup.py ├── create_vm_v3_detailed │ ├── create_vm_v3_detailed.json │ ├── create_vm_v3_detailed.py │ ├── readme.rst │ └── setup.py ├── get_cluster_info_v3 │ ├── .gitignore │ ├── get_cluster_info_v3.py │ ├── readme.rst │ ├── requirements.txt │ ├── screenshot_html.png │ ├── setup.py │ └── templates │ │ └── nutanixv3.html.example ├── get_energy_stats │ ├── .gitignore │ ├── README.md │ ├── get_cluster_energy_stat.py │ └── requirements.txt ├── get_host_details │ ├── .gitignore │ ├── get_host_details.png │ ├── get_host_details.py │ ├── get_host_details_spreadsheet.png │ ├── readme.rst │ └── setup.py ├── launch_calm_blueprint │ ├── api_client │ │ └── __init__.py │ ├── environment_options │ │ └── __init__.py │ ├── exceptions │ │ └── __init__.py │ ├── launch_calm_blueprint_v3.py │ ├── readme.rst │ ├── screenshot.png │ ├── screenshot_no_debug.png │ └── setup.py ├── list_vm_v3_large │ ├── .gitignore │ ├── list_vm_v3_large.json │ ├── list_vm_v3_large.json.sample │ ├── list_vm_v3_large.py │ ├── readme.rst │ └── script_output.png ├── nutanix_objects │ ├── .gitignore │ ├── README.md │ ├── multiple_buckets.py │ ├── requirements.txt │ ├── screenshot_upload_files.png │ └── upload_file.py ├── sample-chatbot │ ├── .gitignore │ ├── .streamlit │ │ └── config.toml │ ├── LICENSE │ ├── NOTICES │ ├── README.md │ ├── chat.py │ ├── nutanix.svg │ └── requirements.txt ├── script_output.png ├── v4api_client │ ├── README.md │ ├── list_images_client.py │ ├── requirements.txt │ └── update_image_etag_client.py └── v4api_sdk │ ├── .gitignore │ ├── README.md │ ├── api_key_auth_sdk.py │ ├── batch_ops_actions.py │ ├── batch_ops_create.py │ ├── batch_ops_modify.py │ ├── categories │ ├── .gitignore │ ├── Categories V4 Workflow Documentation.postman_collection.json │ ├── LICENSE │ ├── NOTICES │ ├── README.md │ ├── categories_v4_workflow.py │ └── requirements.txt │ ├── category_specs.json │ ├── create_categories.py │ ├── create_image_sdk.py │ ├── create_network_security_policy.py │ ├── create_subnet_sdk.py │ ├── create_vm_sdk.py │ ├── docs │ └── index.md │ ├── dr │ ├── .gitignore │ ├── LICENSE │ ├── NOTICES │ ├── README.md │ ├── cbt_api_code.py │ ├── requirements.txt │ └── vss_api_code.py │ ├── generate_report.py │ ├── generate_report_config.py │ ├── get_vm_stats_sdk.py │ ├── lcm_updates.png │ ├── lcm_updates.py │ ├── lcm_updates_v2.png │ ├── list_images_sdk.py │ ├── requirements.txt │ ├── screenshot_batch_create.png │ ├── screenshot_batch_modify.png │ ├── screenshot_create_cats.png │ ├── screenshot_create_image.png │ ├── screenshot_create_nsp1.png │ ├── screenshot_create_nsp2.png │ ├── screenshot_create_subnet.png │ ├── screenshot_create_vm.png │ ├── screenshot_list_images.png │ ├── screenshot_update_image_etag.png │ ├── startup-example.json │ ├── startup.py │ ├── subnet_config.json │ ├── tme │ ├── __init__.py │ ├── apiclient.py │ ├── test.py │ └── utils.py │ ├── update_image_etag_sdk.py │ └── userdata.yaml ├── readme.md └── shell ├── batch_request_simple ├── batch_request_simple ├── batch_request_simple.json ├── readme.rst └── script_output.png ├── create_vm_v3_basic ├── create_vm_v3_basic ├── create_vm_v3_basic.json ├── readme.rst └── script_output.png ├── readme.rst └── script_output.png /.disclaimer: -------------------------------------------------------------------------------- 1 | These code samples are intended as a standalone examples. Subject to licensing restrictions defined on Nutanix.dev, these can be downloaded, copied and/or modified in any way you see fit. Please be aware that all public code samples provided by Nutanix are unofficial in nature, are provided as examples only, are unsupported and will need to be heavily scrutinized and potentially modified before they can be used in a production environment. All such code samples are provided on an as-is basis, and Nutanix expressly disclaims all warranties, express or implied. All code samples are © Nutanix, Inc., and are provided as-is under the MIT license (https://opensource.org/licenses/MIT). -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | venv/ 4 | .vscode/ 5 | 6 | .metrics 7 | *.pdf 8 | *.html 9 | 10 | *.pyc 11 | __pycache__/ 12 | 13 | .pytest_cache/ 14 | .coverage 15 | htmlcov/ 16 | 17 | dist/ 18 | build/ 19 | *.egg-info/ 20 | 21 | *.log 22 | *.swp 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Nutanix 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /blueprints/centos8_docker_flask/.disclaimer: -------------------------------------------------------------------------------- 1 | This code is intended as a standalone example. Subject to licensing restrictions defined on nutanix.dev, this can be downloaded, copied and/or modified in any way you see fit. Please be aware that all public code samples provided by Nutanix are unofficial in nature, are provided as examples only, are unsupported and will need to be heavily scrutinized and potentially modified before they can be used in a production environment. All such code samples are provided on an as-is basis, and Nutanix expressly disclaims all warranties, express or implied. All code samples are © Nutanix, Inc., and are provided as-is under the MIT license (https://opensource.org/licenses/MIT). -------------------------------------------------------------------------------- /blueprints/centos8_docker_flask/README.md: -------------------------------------------------------------------------------- 1 | # Nutanix Calm Blueprint - Python Flask App on Docker 2 | 3 | This blueprint will create a small demo application that provides the following capabilities: 4 | 5 | - Creates a CentOS 8 VM that has been configured with an SSH username, SSH keys, `vim`, `git` 6 | - Installs and configures `firewalld` for app-specific TCP ports 7 | - Installs Python 3.8 8 | - Installs Docker and Docker Compose 9 | - Creates and configures a virtual environment for our Python app 10 | - Launches required Docker containers using the provided `docker-compose.yml` and `Dockerfile` files 11 | - Install dependencies within the container using the Python-standard `requirements.txt` file 12 | - Exposes TCP port 5001 on the container so that users can access the Python Flask app 13 | 14 | ## Intended Audience 15 | 16 | There is assumption that users of this blueprint have previous exposure to the Nutanix Calm UI, in particular: 17 | 18 | - Uploading blueprints 19 | - Launching blueprints 20 | - Retrieving launched application information e.g. virtual machine/service IP addresses 21 | - Monitoring of launch progress using the **Audit** tab 22 | 23 | ## The App 24 | 25 | A screenshot of the created app is shown below: 26 | 27 | ![App running](./images/screenshot.png) 28 | 29 | ## Requirements 30 | 31 | - Prism Central 5.19 or later 32 | - Nutanix Calm 3.0 or later 33 | - Prism Central and Prism Element credentials (read-only credentials are fine) 34 | 35 | *Note:* Due to this apps's basic nature, it is assumed your Prism Central and Prism Element environments use identical credentials 36 | 37 | ## Usage 38 | 39 | 1. Clone this repo: 40 | 41 | - Either using the terminal: 42 | 43 | ``` 44 | git clone https://github.com/nutanixdev/code-samples 45 | ``` 46 | 47 | **or**: 48 | 49 | - Download a complete copy of this repository using the **Download** button provided by GitHub 50 | 51 | 2. Login to Prism Central 52 | 3. From the "hamburger" or ellipsis menu, select **Services** 53 | 4. Open Nutanix Calm 54 | 5. Using the **Upload Blueprint** option, upload the `centos8_docker_flask.json` blueprint file from the **blueprints/centos8_docker_flask** directory 55 | 6. When prompted, please select an appropriate Calm project for your environment 56 | 57 | *Note:* This setting will be different for all users 58 | 59 | 7. When prompted, enter **nutanix/4u** as the blueprint password (this will allow the blueprint to import preconfigured SSH credentials) 60 | 8. Launch the app using the **Launch** option 61 | 62 | - Defaults have been entered for the location of our Python app; this is simply used to demonstrate Nutanix Calm's ability to accept input from the user and don't need to be changed for this demo 63 | - **Environment** and **App Profile** shouldn't need to be changed 64 | 65 | 9. When the app has finished launching, browse to the VM's IP address on port 5001 66 | 67 | To get the IP address for a Calm managed virtual machine, please see the example screenshot below: 68 | 69 | ![Running service's IP address](./images/service_ip_address.png) 70 | 71 | *Note:* The app will install CentOS 8 then update all system packages. Depending on the speed of your internet connection and on how many packages there are to update, this can take some time. 72 | 73 | ## Creating The App 74 | 75 | If you are interested in creating this app from scratch, full and detailed steps have been published in the Nutanix DevOps Marketing lab entitled [Python 3 Flask dashboard](https://www.nutanix.dev/labs/python-flask-dashboard/). 76 | 77 | This lab will walk you through creating this from an empty directory, including all dependencies, explanations of the various AJAX calls from JavaScript and Python, as well as the Nutanix Prism Element and Prism Central API requests made by the app. 78 | 79 | Please note the lab is designed to create the app for local use vs this repository that runs the same app within a Docker container. 80 | 81 | ## License 82 | 83 | Please see the accompanying `LICENSE` file that is distributed with this repository. 84 | 85 | ## Disclaimer 86 | 87 | Please see the `.disclaimer` file that is distributed with this repository. 88 | -------------------------------------------------------------------------------- /blueprints/centos8_docker_flask/images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/blueprints/centos8_docker_flask/images/screenshot.png -------------------------------------------------------------------------------- /blueprints/centos8_docker_flask/images/service_ip_address.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/blueprints/centos8_docker_flask/images/service_ip_address.png -------------------------------------------------------------------------------- /csharp/app_running.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/csharp/app_running.png -------------------------------------------------------------------------------- /csharp/app_running_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/csharp/app_running_large.png -------------------------------------------------------------------------------- /csharp/configure_console_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/csharp/configure_console_app.png -------------------------------------------------------------------------------- /csharp/list_vm_v3/readme.rst: -------------------------------------------------------------------------------- 1 | C# Code Samples - list_vm_v3.cs 2 | ############################### 3 | 4 | This readme file is specifically for the **list_vm_v3.cs** C# console app. 5 | 6 | The setup instructions are the same as all other console apps in this repository. This file is provided as additional/supplemental information for this specific code sample. 7 | 8 | Please see the `main `_ page for general instructions. 9 | 10 | Code Sample Details 11 | ................... 12 | 13 | A quick intro, first. The **list_vm_v3.cs** code sample shows a basic demo of REST API interactions with C#. 14 | 15 | Please note there is no specific provision for environments of a specific size as all API requests will be made with the default parameters. For example: 16 | 17 | - A maximum of 20 entities are returned with each request 18 | - No offset has been specified i.e. every request will return the first 20 VMs **only** 19 | - If you are looking for code appropriate for use in large environments, please see the `list_vm_v3_large `_ code sample. 20 | - A final prompt ensures the console app doesn't "flash" before the user can view the output. 21 | 22 | Please make sure to modify the code appropriately before you use it in production. 23 | 24 | An example of the console application's output is shown below: 25 | 26 | .. figure:: ../app_running.png 27 | -------------------------------------------------------------------------------- /csharp/list_vm_v3_large/readme.rst: -------------------------------------------------------------------------------- 1 | C# Code Samples - list_vm_v3_large.cs 2 | ##################################### 3 | 4 | This readme file is specifically for the **list_vm_v3_large.cs** C# console app. 5 | 6 | The setup instructions are the same as all other console apps in this repository. This file is provided as additional/supplemental information for this specific code sample. 7 | 8 | Please see the main_ page for general instructions. 9 | 10 | Code Sample Details 11 | ................... 12 | 13 | A quick intro, first. The **list_vm_v3.cs** code sample shows a basic demo of REST API interactions with C#. There is no provision for environments of a specific size as all API requests will be made with the default parameters. For example: 14 | 15 | - A maximum of 20 entities are returned with each request 16 | - No offset has been specified i.e. every request will return VMs starting 0-19 17 | 18 | In large environments this information is not overly useful. 19 | 20 | **list_vm_v3_large.cs** has been provided with a number of additional capabilities and "architecture" choices: 21 | 22 | - Clusters with >500 VMs will be identified. 23 | - A single request will be made if the cluster has <=500 VMs i.e. VM 0-499. 24 | - Additional requests will be made for VMs 500-n (where n is the total number of VMs in the cluster). 25 | - The API request "work" has been broken out into a dedicated **RESTClient** class that exposes a public **SendRequest** method. 26 | - The **RESTClient** class constructor accepts an array of parameters so that a single instance of the **RESTClient** class can be reused. 27 | - The **SendRequest** method returns an instance of **RequestResponse**. 28 | - **RequestResponse** contains public properties for a response **Code**, **Message** and **Details**, making it easy to see what the request result was in the event of a caught exception. 29 | - The **SendRequest** method will be called as many times as necessary so that all VMs are captured. For example: 30 | 31 | - A cluster with 1407 VMs will have the **SendRequest** method called three times. 32 | - The first request will returns VMs 0-499 (500 VMs). 33 | - The second request will return VMs 500-999 (500 VMs). 34 | - The third and final request will return VMs 1000-406 (407 VMs). 35 | 36 | - A final prompt ensures the console app doesn't "flash" before the user can view the output. 37 | 38 | While this demo is considerably more "advanced" than the standard **list_vm_v3.cs** demo, please still make sure to modify the code appropriately before you use it in production. 39 | 40 | An example of the console application's output is shown below: 41 | 42 | .. figure:: ../app_running_large.png 43 | 44 | .. _main: https://github.com/nutanixdev/code-samples/tree/master/csharp -------------------------------------------------------------------------------- /csharp/new_console_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/csharp/new_console_app.png -------------------------------------------------------------------------------- /csharp/new_project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/csharp/new_project.png -------------------------------------------------------------------------------- /csharp/readme.rst: -------------------------------------------------------------------------------- 1 | Nutanix Developer Portal Code Samples - C# 2 | ########################################## 3 | 4 | To use the C# code samples, the following environment is recommended. 5 | 6 | - `Visual Studio Community `_ (free & recommended) 7 | - Visual Studio "full" edition (commercial software) 8 | - Access to a Nutanix Cluster for testing API v2.0 requests 9 | - Access to Prism Central for API v3 requests 10 | - Nutanix Community Edition is supported but may not always provide the exact same APIs as a "full" Nutanix cluster. 11 | - The Newtonsoft.Json extension for .NET. To install Newtonsoft.Json, please see the official `documentation `_. **This will need to be done before continuing below**. 12 | 13 | .. note:: Please note that instructions provided in this repository will assume the use of Visual Studio Community software. 14 | 15 | Console Applications 16 | .................... 17 | 18 | The provided C# console applications are designed to demonstrate use of the Nutanix Prism REST APIs from C#. To use the samples in your environment, please follow the instructions below. 19 | 20 | The examples and screenshots below are from the **list_vm_vs/list_vm_v3.cs** sample. 21 | 22 | #. Open Visual Studio Community_ 23 | #. Select **Create a new project** 24 | 25 | .. figure:: new_project.png 26 | 27 | #. Select **Console App (.NET Framework)** from the list of options (it may be easier to search for **console** in the search bar) 28 | 29 | .. figure:: new_console_app.png 30 | 31 | #. Click **Next** and configure the app as appropriate for your environment (example shown below). 32 | 33 | .. figure:: configure_console_app.png 34 | 35 | #. Click **Create** 36 | 37 | #. Add a reference to **NewtonSoft.Json**: 38 | 39 | - Click **View** > **Other Windows** > **Package Manager Console** 40 | - Enter the following command: 41 | 42 | .. code-block:: bash 43 | 44 | Install-Package Newtonsoft.Json -Version 12.0.2 45 | 46 | #. Add a reference to **System.Web.Extensions** - this is required for the **System.Web.Script.Serialization** that some code samples use: 47 | 48 | - Right-click **References** in the Solution Explorer and select **Add Reference** 49 | - Find **System.Web.Extensions** in the list and check the box next to it (the checkbox won't be visible until you mouse over the option) 50 | - Click OK 51 | 52 | #. When the new console application is created, the default Program.cs contents can be completely replaced (copied/pasted) with the code from the repository sample you are using. 53 | 54 | - Tip: Make sure you replace **all** the existing contents of Program.cs, including all **Using** statements at the top. 55 | 56 | #. In the default sample code, edit **ClusterIp**, **ClusterUsername** and **ClusterPassword** variables so they are correct for your environment. 57 | 58 | #. Either build (Ctrl-Shift-B) or run (F5) the application. The complete JSON response will be shown in the console application window. 59 | 60 | #. The screenshots below show two examples: 61 | 62 | - An example of a console app aimed at small environments with fewer than 500 VMs. This is taken from **list_vm_v3.cs**. 63 | - An example of a console app designed for larger environments i.e. more than 500 VMs. This is taken from **list_vm_v3_large.cs**. 64 | 65 | .. figure:: app_running.png 66 | .. figure:: app_running_large.png 67 | 68 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Nutanix Code Samples 2 | 3 | Coming soon. 4 | -------------------------------------------------------------------------------- /go/batch_requests/batch_requests: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/go/batch_requests/batch_requests -------------------------------------------------------------------------------- /go/batch_requests/batch_requests.go: -------------------------------------------------------------------------------- 1 | /* 2 | Send Batch calls or multiple requests in one API Call using v3 API batch endpoint 3 | This script uses a JSON file "batch_requests.json". 4 | If the file is in the same directory as the go binary the code can be run as is 5 | You can also have the code point to a file using 6 | $ go run batchapi.go -file= 7 | or 8 | $ ./batchapi -file= 9 | Two batch calls in JSON file; 1st creates a basic VM , 2nd call creates an Image from URL 10 | */ 11 | package main 12 | 13 | import ( 14 | "bytes" 15 | "crypto/tls" 16 | "flag" 17 | "fmt" 18 | "io/ioutil" 19 | "log" 20 | "net/http" 21 | 22 | "github.com/tidwall/gjson" 23 | ) 24 | 25 | const ( 26 | pcUser string = "admin" // PC User 27 | pcPass string = "" // PC Password 28 | pcIp string = ":9440" // PC Cluster VIP 29 | pcUrl string = "/api/nutanix/v3" // URL for v2 API 30 | pcObj string = "/batch" // endpoint for batch calls 31 | ) 32 | 33 | // Error handling function 34 | func exitOnError(msg string, err error) { 35 | if err != nil { 36 | fmt.Println(msg) 37 | fmt.Println(err) 38 | log.Fatal() 39 | } 40 | } 41 | 42 | // Basic Post request function for posting data using v3 POST calls 43 | func basicPost(pcObj string, jsonByteData []byte) (string, int, error) { 44 | var bodyTextStr string 45 | var httpCode int 46 | tr := &http.Transport{ 47 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 48 | } 49 | client := &http.Client{Transport: tr} 50 | URL := "https://" + pcIp + pcUrl + pcObj 51 | fmt.Println(fmt.Sprintf(`Posting data to URL: %s`, URL)) 52 | payloadData := bytes.NewBuffer(jsonByteData) 53 | req, err := http.NewRequest("POST", URL, payloadData) 54 | req.Header.Set("Content-Type", "application/json") 55 | req.SetBasicAuth(pcUser, pcPass) 56 | resp, err := client.Do(req) 57 | if err != nil { 58 | fmt.Println("Error: ", err) 59 | } else { 60 | bodyText, _ := ioutil.ReadAll(resp.Body) 61 | httpCode = int(resp.StatusCode) 62 | bodyTextStr = string(bodyText) 63 | } 64 | return bodyTextStr, httpCode, err 65 | } 66 | 67 | func main() { 68 | 69 | // Use flag to get value for filename from cli 70 | // Default filename is batch_requests.json in the same location as the go code. 71 | fileName := flag.String("file", "batch_requests.json", "filename for batch request payload") 72 | flag.Parse() 73 | 74 | // Read JSON File 75 | requestByteData, err := ioutil.ReadFile(*fileName) 76 | exitOnError("Error in accessing file", err) 77 | 78 | // Convert read byte value to string for GJSON 79 | requestString := string(requestByteData) 80 | 81 | // Extract the payload to be sent in the post call 82 | result := gjson.Get(requestString, "batch_details") 83 | 84 | // Convert JSON payload to byte array for POST call 85 | batchPayload := []byte(result.String()) 86 | 87 | resp, code, err := basicPost(pcObj, batchPayload) 88 | exitOnError("Error in sending POST Call", err) 89 | 90 | // Condition when request was successful 91 | if code == 200 { 92 | statusCodes := gjson.Get(string(resp), "api_response_list.#.status") 93 | for ind, code := range statusCodes.Array() { 94 | if code.Int() == 202 { 95 | fmt.Println("Request Successful; Entity Created") 96 | } else { 97 | fmt.Printf("Status code for entity %d: %d\n", ind, code.Int()) 98 | } 99 | } 100 | } else { 101 | fmt.Println("HTTP request not successful") 102 | fmt.Printf("HTTP status Code %d\n", code) 103 | fmt.Printf("HTTP Response body %s\n", string(resp)) 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /go/batch_requests/batch_requests.json: -------------------------------------------------------------------------------- 1 | { 2 | "batch_details":{ 3 | "action_on_failure": "CONTINUE", 4 | "execution_order": "SEQUENTIAL", 5 | "api_request_list": [ 6 | { 7 | "operation": "POST", 8 | "path_and_params": "/api/nutanix/v3/vms", 9 | "body": { 10 | "spec": { 11 | "cluster_reference": { 12 | "kind": "cluster", 13 | "uuid": "", 14 | "name": "" 15 | }, 16 | "name": "vm_from_batch_1000", 17 | "resources": {} 18 | }, 19 | 20 | "metadata": { 21 | "kind": "vm" 22 | } 23 | } 24 | }, 25 | { 26 | "operation": "POST", 27 | "path_and_params": "/api/nutanix/v3/images", 28 | "body": { 29 | "spec": { 30 | "name": "image_from_batch_1000", 31 | "resources": { 32 | "image_type": "DISK_IMAGE", 33 | "source_uri": "https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-1905.qcow2" 34 | }, 35 | "description": "Image created via v3 API batch request" 36 | }, 37 | "api_version": "3.1.0", 38 | "metadata": { 39 | "kind": "image", 40 | "categories": {}, 41 | "name": "image_from_batch_1000" 42 | } 43 | } 44 | } 45 | ], 46 | "api_version": "3.0" 47 | } 48 | } -------------------------------------------------------------------------------- /go/batch_requests/readme.rst: -------------------------------------------------------------------------------- 1 | ##################### 2 | Batch Request with Go 3 | ##################### 4 | 5 | Golang script to send batch tasks to Prism Central via v3 API. 6 | 7 | ************ 8 | Requirements 9 | ************ 10 | 11 | Please refer to `Nutanix Developer Portal Go samples `_ link for dependencies. 12 | 13 | ******* 14 | Details 15 | ******* 16 | 17 | This script sends batch v3 API calls to Prism Central to perform a set of tasks. The tasks are defined in the batch_request.json file. 18 | 19 | ***** 20 | Usage 21 | ***** 22 | 23 | To use this script, please following these steps: 24 | 25 | - Edit **batch_requests.go** so that the environment values match your settings i.e. Prism Central IP etc 26 | - Edit **batch_requests.json** to match your environment, in particular the cluster name and UUID 27 | 28 | The script requires batch_requests.json as file as this file contains the payload for the batch call. 29 | 30 | You can leave the file in the same directory as the go binary or point the code to the file location during run time. 31 | 32 | Usage Image: 33 | 34 | .. figure:: screenshot.png 35 | 36 | **** 37 | Note 38 | **** 39 | 40 | The json payload file contains a cluster reference that needs to be edited. This must be the UUID of the cluster on which to create the VM and image as per the sample JSON payload file provided with this script. 41 | 42 | Cluster UUID can be obtained by running “ncli cluster info” from Prism Element CVM or by using the Nutanix Prism APIs to request cluster details. 43 | -------------------------------------------------------------------------------- /go/batch_requests/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/go/batch_requests/screenshot.png -------------------------------------------------------------------------------- /go/multiple_vm_clone/multiple_vm_clone.go: -------------------------------------------------------------------------------- 1 | /* 2 | Create multiple clones of the VM in a specified network using v2 API 3 | The script creates 3 clones of the specified VM 4 | Requires, Name and Target for the clone 5 | Rest of the reaource settings can be edited within the JSON function. 6 | */ 7 | 8 | package main 9 | 10 | import ( 11 | "bytes" 12 | "crypto/tls" 13 | "fmt" 14 | "io/ioutil" 15 | "log" 16 | "net/http" 17 | 18 | "github.com/tidwall/gjson" 19 | ) 20 | 21 | var ( 22 | peUser string = "admin" // PE Username 23 | pePass string = " " // PE Password 24 | peIp string = ":9440" // PE Cluster VIP 25 | peUrl string = "/PrismGateway/services/rest/v2.0/" // URL for v2 API 26 | vmName string = "" // VM to be cloned 27 | network_uuid string = "" // Network UUID for the cloned VMs 28 | cloneNameList = []string{"vm_clone1_name", "vm_clone2_name", "vm_clone3_name"} // Clone Names 29 | vmNameUUidMap map[string]string 30 | testMap map[string]string 31 | ) 32 | 33 | // Basic Get Request function for v2 GET calls 34 | func basicGet(peObj string) (string, error) { 35 | var bodyTextStr string 36 | testMap = make(map[string]string) 37 | tr := &http.Transport{ 38 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 39 | } 40 | client := &http.Client{Transport: tr} 41 | URL := "https://" + peIp + peUrl + peObj 42 | fmt.Println(fmt.Sprintf(`Getting data from URL: %s`, URL)) 43 | req, err := http.NewRequest("GET", URL, nil) 44 | if err != nil { 45 | fmt.Println("Error creating HTTP request") 46 | log.Fatal() 47 | } 48 | req.Header.Set("ContentType", "application/json") 49 | req.SetBasicAuth(peUser, pePass) 50 | resp, err := client.Do(req) 51 | if err != nil { 52 | fmt.Println("Error: ", err) 53 | } else { 54 | bodyText, _ := ioutil.ReadAll(resp.Body) 55 | bodyTextStr = string(bodyText) 56 | } 57 | return bodyTextStr, err 58 | } 59 | 60 | // Basic Post request function for posting data using v2 POST calls 61 | func basicPost(peObj string, jsonByteData []byte) (string, int, error) { 62 | var bodyTextStr string 63 | var httpCode int 64 | tr := &http.Transport{ 65 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 66 | } 67 | client := &http.Client{Transport: tr} 68 | URL := "https://" + peIp + peUrl + peObj 69 | fmt.Println(fmt.Sprintf(`Posting data to URL: %s`, URL)) 70 | payloadData := bytes.NewBuffer(jsonByteData) 71 | req, err := http.NewRequest("POST", URL, payloadData) 72 | req.Header.Set("ContentType", "application/json") 73 | req.SetBasicAuth(peUser, pePass) 74 | resp, err := client.Do(req) 75 | if err != nil { 76 | fmt.Println("Error: ", err) 77 | } else { 78 | bodyText, _ := ioutil.ReadAll(resp.Body) 79 | httpCode = int(resp.StatusCode) 80 | bodyTextStr = string(bodyText) 81 | } 82 | return bodyTextStr, httpCode, err 83 | } 84 | 85 | // Payload JSON data for cloning the VM; takes clone Name as input 86 | // Requires Network UUID of the network the Clone will be in 87 | // Network UUID can be obtained usinag acli net.list on the CVM 88 | func enterCloneName(cloneName string) []byte { 89 | var postData string = fmt.Sprintf(`{ 90 | "spec_list": 91 | [ 92 | { 93 | "name":"%s", 94 | "memory_mb":4096, 95 | "num_vcpus":4, 96 | "num_cores_per_vcpu":1, 97 | "vm_nics": 98 | [ 99 | { 100 | "network_uuid":"`+network_uuid+`" 101 | } 102 | ], 103 | "override_network_config":true, 104 | "clone_affinity":false 105 | } 106 | ] 107 | }`, cloneName) 108 | postDataByte := []byte(postData) 109 | return postDataByte 110 | 111 | } 112 | 113 | // Get uuid of the VM which is to be cloned 114 | func getVMUUid(vmObj, vmName string) (string, error) { 115 | fmt.Println("In get VM uuid ") 116 | vmNameUUidMap = make(map[string]string) 117 | vmData, err := basicGet(vmObj) 118 | if err != nil { 119 | fmt.Println("Error getting VM uuid") 120 | fmt.Println(err) 121 | log.Fatal() 122 | } 123 | vmNameJ := gjson.Get(vmData, "entities.#.name") 124 | vmUuidJ := gjson.Get(vmData, "entities.#.uuid") 125 | for ind1, name := range vmNameJ.Array() { 126 | for ind2, uuid := range vmUuidJ.Array() { 127 | if ind1 == ind2 { 128 | vmNameUUidMap[name.String()] = uuid.String() 129 | } 130 | } 131 | } 132 | return vmNameUUidMap[vmName], err 133 | } 134 | 135 | // Clone source VM using POST v2 call to the /clone endpoint 136 | // requires vm uuid , clone api endpoint and clone Name 137 | func cloneVM(cloneName, vmObj, vmUuid string) (string, int) { 138 | cloneByteData := enterCloneName(cloneName) 139 | peObj := "vms/" + vmUuid + "/clone" 140 | resp, code, _ := basicPost(peObj, cloneByteData) 141 | return resp, code 142 | } 143 | 144 | func main() { 145 | vmObj := "vms" 146 | vmUuid, err := getVMUUid(vmObj, vmName) 147 | fmt.Printf(`VM uuid for %s is %s \n`, vmName, vmUuid) 148 | if err != nil { 149 | fmt.Printf(`VM uuid for VM %s not found \n`, vmName) 150 | fmt.Println(err) 151 | log.Fatal() 152 | } 153 | fmt.Sprintf(`Cloning for VM %s %s`, vmName, vmUuid) 154 | for _, cloneName := range cloneNameList { 155 | resp, code := cloneVM(cloneName, vmObj, vmUuid) 156 | if code == 201 { 157 | fmt.Printf(`Http code %d: Clone %s created for %s \n`, code, cloneName, vmName) 158 | fmt.Println(resp) 159 | } else { 160 | fmt.Println("Clone not created refer HTTP response body below: ") 161 | fmt.Println(resp) 162 | } 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /go/multiple_vm_clone/multiple_vm_clone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/go/multiple_vm_clone/multiple_vm_clone.png -------------------------------------------------------------------------------- /go/multiple_vm_clone/readme.rst: -------------------------------------------------------------------------------- 1 | Go Code Samples - multiple_vm_clone.go 2 | ###################################### 3 | 4 | This readme file is specifically for the **multiple_vm_clone.go** Go code sample. 5 | 6 | To run this code sample, please ensure the following requirements are met: 7 | 8 | #. Go is already `installed on your system `_ 9 | 10 | #. You have the **github.com/tidwall/gjson** package installed: 11 | 12 | .. code-block:: bash 13 | 14 | go get -u github.com/tidwall/gjson 15 | 16 | Code Sample Details 17 | ................... 18 | 19 | This Go code sample creates multiple clones of the specified VM in a specified network using the Nutanix Prism Element v2.0 API. 20 | 21 | JSON Parameters 22 | ............... 23 | 24 | The cloned VM parameters are specified via the JSON object within the **enterCloneName** function. Please modify the parameters there if the example parameters are not suitable for your environment. 25 | 26 | Usage 27 | ----- 28 | 29 | #. Build the script: 30 | 31 | .. code-block:: bash 32 | 33 | go build 34 | 35 | #. Run the compiled program: 36 | 37 | .. code-block:: bash 38 | 39 | ./multiple_clone_vm 40 | 41 | Sample Screenshot 42 | ----------------- 43 | 44 | The screenshot shows the script being built and run. 45 | 46 | Note: The system used in the screenshot already has the github.com/tidwall/gjson package installed. 47 | 48 | .. figure:: ./multiple_vm_clone.png -------------------------------------------------------------------------------- /go/readme.rst: -------------------------------------------------------------------------------- 1 | Go Code Samples 2 | ############### 3 | 4 | Please see the readme.rst file in each code sample's folder. 5 | 6 | Each Go code sample has been individually documented with specific usage instructions. 7 | 8 | Requirements for all Go Code Samples 9 | ------------------------------------ 10 | 11 | To run the Go code samples, please ensure the following requirements are met: 12 | 13 | #. Go is already `installed on your system `_ 14 | 15 | #. In addition to the requirements list per-sample, you should have the **github.com/tidwall/gjson** package installed: 16 | 17 | .. code-block:: bash 18 | 19 | go get -u github.com/tidwall/gjson 20 | -------------------------------------------------------------------------------- /go/v4api_sdk/.gitignore: -------------------------------------------------------------------------------- 1 | go.mod 2 | go.sum 3 | -------------------------------------------------------------------------------- /go/v4api_sdk/README.md: -------------------------------------------------------------------------------- 1 | # Nutanix v4 SDK Sample Script 2 | 3 | Code sample to demonstrate use of the new Nutanix v4 APIs via Go SDK. 4 | 5 | Requires Prism Central 2024.1 or later and AOS 6.8 or later 6 | 7 | ## Usage 8 | 9 | Example instructions are for a Linux or Mac OS X environment. 10 | 11 | - Install Go in your local environment as per the [Go documentation](https://go.dev/doc/install) 12 | - Create folder for your Go development (example only) 13 | 14 | ``` 15 | mkdir ~/godev 16 | cd ~/godev 17 | ``` 18 | 19 | - Install dependencies, including the Nutanix Go SDKs: 20 | 21 | ``` 22 | go mod init nutanixdev/v4api_sdk 23 | go get github.com/nutanix/ntnx-api-golang-clients/vmm-go-client/v4/...@v4.0.1-beta.1 24 | go get golang.org/x/term 25 | ``` 26 | 27 | - Run script: 28 | 29 | ``` 30 | go run list_images_sdk.go -pc_ip= -username= [-debug] 31 | ``` 32 | 33 | Note: User will be prompted for password. If `-debug` is specified, additional debug information will be shown during script execution. 34 | 35 | ## Screenshot 36 | 37 | ![Example script execution](./screenshot.png "Example script execution") 38 | 39 | -------------------------------------------------------------------------------- /go/v4api_sdk/list_images_sdk.go: -------------------------------------------------------------------------------- 1 | // list_images_sdk.go 2 | // 3 | // Code sample showing basic usage of the Nutanix v4 API SDK for Go(lang) 4 | // 5 | // This demo connects to Prism Central, authenticates then returns a list of images, 6 | // displays the image names and their size in bytes 7 | // 8 | // Requirements: 9 | // 10 | // - Prism Central pc.2024.1 or later and AOS 6.8 or later 11 | 12 | package main 13 | 14 | import ( 15 | "fmt" 16 | "os" 17 | "flag" 18 | "reflect" 19 | "github.com/nutanix/ntnx-api-golang-clients/vmm-go-client/v4/api" 20 | "github.com/nutanix/ntnx-api-golang-clients/vmm-go-client/v4/client" 21 | v4sdkimages "github.com/nutanix/ntnx-api-golang-clients/vmm-go-client/v4/models/vmm/v4/content" 22 | v4sdkerror "github.com/nutanix/ntnx-api-golang-clients/vmm-go-client/v4/models/vmm/v4/error" 23 | "golang.org/x/term" 24 | ) 25 | 26 | var ( 27 | ApiClientInstance *client.ApiClient 28 | ImagesApiInstance *api.ImagesApi 29 | ) 30 | 31 | func main() { 32 | 33 | // setup the accepted command line arguments 34 | pc_ip := flag.String("pc_ip", "undefined", "Prism Central IP or FQDN") 35 | username := flag.String("username", "undefined", "Prism Central Username") 36 | debug := flag.Bool("debug", false, "Enable/disable some extra debug info") 37 | flag.Parse() 38 | 39 | // make sure the user has provided both Prism Central IP address/FQDN and username 40 | if *pc_ip == "undefined" || *username == "undefined" { 41 | fmt.Println("Please make sure you have specified both pc_ip and username. Usage example:") 42 | fmt.Println("go run list_images_sdk.go -pc_ip=10.10.10.10 -username=admin") 43 | panic("Insufficient command line arguments; exiting") 44 | } 45 | 46 | // show some intro info i.e. PC IP and username provided by the user 47 | fmt.Println("Prism Central IP or FQDN:", *pc_ip) 48 | fmt.Println("Username:", *username) 49 | 50 | // accept a hidden password from the user 51 | fmt.Print("Enter your Prism Central password (won't be shown on screen): ") 52 | password, err := term.ReadPassword(int(os.Stdin.Fd())) 53 | if err != nil { 54 | panic(err) 55 | } 56 | 57 | // not recommended; uncomment this line to show the entered password in the terminal 58 | // really only useful for debugging e.g. if a password is entered that causes some sort of issue 59 | // fmt.Println("Password:", string(password)) 60 | 61 | // create the API client instance and configure connection parameters 62 | ApiClientInstance = client.NewApiClient() 63 | ApiClientInstance.Host = *pc_ip 64 | ApiClientInstance.Port = 9440 65 | ApiClientInstance.RetryInterval = 100 66 | ApiClientInstance.MaxRetryAttempts = 2 67 | ApiClientInstance.VerifySSL = false 68 | ApiClientInstance.Username = *username 69 | ApiClientInstance.Password = string(password) 70 | // debug property is set to true or false depending on use of -debug command line argument 71 | // defaults to false 72 | ApiClientInstance.Debug = *debug 73 | 74 | ImagesApiInstance = api.NewImagesApi(ApiClientInstance) 75 | 76 | page := 0 77 | limit := 20 78 | filter := "" 79 | orderBy := "" 80 | // select is reserved 81 | _select := "" 82 | 83 | // attempt to get the list of images 84 | response, err := ImagesApiInstance.ListImages(&page, &limit, &filter, &orderBy, &_select) 85 | // these errors, if present, can include authentication and connection/timeout issues 86 | if err != nil { 87 | fmt.Println("Request failed:") 88 | panic(err) 89 | } 90 | 91 | // if debug mode is enabled, show some extra debug info 92 | if ApiClientInstance.Debug { 93 | fmt.Println("--- Debug info starts ---") 94 | fmt.Println("*ImagesApiInstance is type", reflect.TypeOf(*ImagesApiInstance)) 95 | fmt.Println("*response.Metadata is type", reflect.TypeOf(*response.Metadata)) 96 | fmt.Println("*response.Data is type", reflect.TypeOf(*response.Data)) 97 | fmt.Println("Length of response.Metadata.Links list is", len(response.Metadata.Links)) 98 | for i := 0; i < len(response.Metadata.Links); i++ { 99 | fmt.Println(*response.Metadata.Links[i].Href) 100 | } 101 | fmt.Println("--- Debug info ends ---") 102 | } 103 | 104 | // show the number of images 105 | fmt.Printf("%d images found\n", *response.Metadata.TotalAvailableResults) 106 | 107 | data := response.GetData() 108 | resultImages, ok := data.([]v4sdkimages.Image) 109 | // make sure no errors were found before trying to display the list of images 110 | if !ok { 111 | // we don't have images i.e. it is an error; do something with the error 112 | err := data.(*v4sdkerror.ErrorResponse) 113 | panic(err) 114 | } 115 | 116 | // if a list of images was found, iterate over and display info about them 117 | for _, value := range resultImages { 118 | // show the image's name 119 | fmt.Printf("Image found with name \"%v\"\n", *value.Name) 120 | 121 | } 122 | 123 | fmt.Println("Done!") 124 | 125 | } 126 | -------------------------------------------------------------------------------- /go/v4api_sdk/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/go/v4api_sdk/screenshot.png -------------------------------------------------------------------------------- /js/v4api_sdk/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | config.json 3 | .eslintrc.json 4 | package-lock.json 5 | package.json 6 | -------------------------------------------------------------------------------- /js/v4api_sdk/README.md: -------------------------------------------------------------------------------- 1 | # Nutanix v4 SDK Sample Script: JS SDK 2 | 3 | Code sample to demonstrate use of the new Nutanix v4 APIs via JS SDK. 4 | 5 | This example demonstrates use of the Nutanix `clustermgmt` JS API library 6 | 7 | ## Usage 8 | 9 | Example instructions are for a Linux or Mac OS X environment. 10 | 11 | - Install Node.js as per the [official documentation](https://nodejs.org/en/download/) 12 | - Add the [Nutanix clustermgmt JS Client](https://www.npmjs.com/package/@nutanix-api/clustermgmt-js-client) as a project dependency; for this demo we are using the `clustermgmt` SDK as it provides access to Cluster APIs: 13 | 14 | ``` 15 | npm install @nutanix-api/clustermgmt-js-client 16 | ``` 17 | 18 | - Optional but useful: Install [ESLint](https://eslint.org/) 19 | 20 | ``` 21 | npm init @eslint/config 22 | ``` 23 | 24 | Answer the questions provided by the install process; the answers to these questions will vary from user to user. 25 | 26 | - Rename `config-example.json` to `config.json` 27 | - Edit `config.json` to include a valid Prism Central IP address and credentials for your environment 28 | - Run the script: 29 | 30 | ``` 31 | node list_clusters_sdk.js 32 | ``` 33 | 34 | ## Screenshot 35 | 36 | ![Example script execution](./screenshot.png "Example script execution") 37 | -------------------------------------------------------------------------------- /js/v4api_sdk/config-example.json: -------------------------------------------------------------------------------- 1 | { 2 | "pc_ip": "", 3 | "pc_port": "9440", 4 | "username": "", 5 | "password": "", 6 | "debug": false 7 | } 8 | -------------------------------------------------------------------------------- /js/v4api_sdk/list_clusters_sdk.js: -------------------------------------------------------------------------------- 1 | /* 2 | * list_clusters_sdk.js 3 | * 4 | * Code sample showing basic usage of the Nutanix v4 API SDK for JS 5 | * 6 | * This demo read configuration from config.json, connects to Prism Central, 7 | * authenticates then returns a list of registered clusters. The list is formatted to show 8 | * cluster names and their extId 9 | * 10 | * Requirements: 11 | * 12 | * Prism Central pc.2024.1 or later and AOS 6.8 or later 13 | */ 14 | 15 | const sdk = require("@nutanix-api/clustermgmt-js-client/dist/lib/index"); 16 | let client = new sdk.ApiClient(); 17 | 18 | client.addDefaultHeader("Accept-Encoding","gzip, deflate, br"); 19 | 20 | const fs = require('fs'); 21 | 22 | // load the configuration from on-disk config.json 23 | fs.readFile('./config.json', 'utf8', (err, data) => { 24 | if (err) { 25 | console.log(`Unable to load config from ./config.json: ${err}`); 26 | } else { 27 | // parse JSON string to JSON object 28 | const config = JSON.parse(data); 29 | 30 | // setup the connection configuration 31 | // for this demo, only Prism Central IP, port, username, password and debug mode are read from on-disk configuration 32 | // Prism Central IPv4/IPv6 address or FQDN 33 | client.host = config.pc_ip; 34 | // HTTP port for connection 35 | client.port = config.pc_port; 36 | // connection credentials 37 | client.username = config.username; 38 | client.password = config.password; 39 | // don't verify SSL certificates; not recommended in production 40 | client.verifySsl = false; 41 | // show extra debug info during demo 42 | client.debug = config.debug; 43 | client.cache = false; 44 | 45 | console.log(`Prism Central IP or FQDN: ${client.host}`); 46 | console.log(`Username: ${client.username}`); 47 | 48 | let clientApi = new sdk.ClustersApi(client); 49 | 50 | // setup request options 51 | var entityListOptions = new Object(); 52 | entityListOptions.page = 0; 53 | entityListOptions.limit = 20; 54 | entityListOptions.filter = ''; 55 | entityListOptions.orderBy = ''; 56 | 57 | clientApi.listClusters(entityListOptions).then(({ data, response }) => { 58 | console.log(`API returned the following status code: ${response.status}`); 59 | data.getData().forEach(element => console.log('Cluster found with name "' + element.name + '"')) 60 | }).catch((err) => { 61 | console.log(`Error is ${err}`); 62 | }) 63 | } 64 | }) 65 | -------------------------------------------------------------------------------- /js/v4api_sdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@nutanix-api/clustermgmt-js-client": "^4.0.1-beta.2" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /js/v4api_sdk/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/js/v4api_sdk/screenshot.png -------------------------------------------------------------------------------- /powershell/batch_request_simple/readme.rst: -------------------------------------------------------------------------------- 1 | Nutanix Developer Portal Code Samples - batch_request_simple.ps1 2 | ################################################################ 3 | 4 | This readme file is specifically for the **batch_request_simple.ps1** PowerShell script. 5 | 6 | The setup instructions are the same as all other PowerShell scripts in this repository. This file is provided as additional/supplemental information for this specific code sample. 7 | 8 | Please see the `main `_ page for general instructions. 9 | 10 | Script Usage 11 | ............ 12 | 13 | Once you have configured your system to run these scripts (see link above), the script can be run as follows. 14 | 15 | #. Edit **batch_request_simple.ps1** and edit the following link to match your Prism Central IP address. 16 | 17 | .. code-block:: powershell 18 | 19 | $parameters.cluster_ip = "10.0.0.1" 20 | 21 | #. Edit **batch_request_simple.ps1** and edit the following variables to suit your requirements: 22 | 23 | .. code-block:: json 24 | 25 | ""name"": ""vm_from_batch"", ` 26 | 27 | .. code-block:: json 28 | 29 | ""name"": ""image_from_batch"" ` 30 | 31 | #. Execute the script: 32 | 33 | .. code-block:: powershell 34 | 35 | batch_request_simple.ps1 36 | 37 | #. Verify the script ran successfully and that the batch API request returned HTTP code 202: 38 | 39 | .. figure:: script_output.png 40 | 41 | #. If you prefer, you can also check Prism Central to ensure the VM and image were both created successfully. -------------------------------------------------------------------------------- /powershell/batch_request_simple/script_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/powershell/batch_request_simple/script_output.png -------------------------------------------------------------------------------- /powershell/check_ps_version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/powershell/check_ps_version.png -------------------------------------------------------------------------------- /powershell/create_vm_v3_basic/create_vm_v3_basic.ps1: -------------------------------------------------------------------------------- 1 | # Nutanix Code Samples 2 | # 3 | # Powershell script to demonstrate basic usage of the Prism REST API v3 4 | # This specific script creates a basic VM similar to the other VM scripts in this repository 5 | 6 | # class to hold our request parameters 7 | # this isn't strictly necessary, but makes the management of related-parameters nice and clean 8 | class RequestParameters { 9 | [string]$cluster_ip 10 | [string]$uri 11 | [string]$username 12 | [string]$password 13 | [string]$payload 14 | [string]$method 15 | [Hashtable]$headers 16 | [int]$timeout 17 | [string]$vm_name 18 | } 19 | 20 | $parameters = [RequestParameters]::new() 21 | 22 | # set the name of the VM that will be created 23 | $parameters.vm_name = "BasicVMViaAPIv3" 24 | 25 | # set the basic properties for the request 26 | $parameters.cluster_ip = "10.0.0.1" 27 | $parameters.uri = "https://" + $parameters.cluster_ip + ":9440/api/nutanix/v3/vms" 28 | 29 | # the payload for this sample script creates a basic VM named as per the $parameters.vm_name variable 30 | # this shows the bare minimum of parameters required to create a VM 31 | # note the vm doesn't get powered on 32 | $parameters.payload = "{ ` 33 | ""spec"": { ` 34 | ""name"":""" + $parameters.vm_name + """, ` 35 | ""resources"":{ ` 36 | } ` 37 | }, ` 38 | ""metadata"":{ ` 39 | ""kind"":""vm"" ` 40 | } ` 41 | }" 42 | 43 | $parameters.method = "POST" 44 | 45 | # set a sensible timeout - you may want to increase this 46 | $parameters.timeout = 5 47 | 48 | # get the user's credentials 49 | # username will be prompted on the command line/within PowerShell 50 | $parameters.username = Read-Host "Enter cluster username" 51 | 52 | # password will prompted using a dialog/popup (because of -AsSecureString) 53 | $secure_password = Read-Host "Enter cluster password" -AsSecureString 54 | 55 | # convert the secure string into a format that is usable by ToBase64String below 56 | # be aware that the result of this is a plain text string - handle it appropriately in production 57 | $binary_string = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure_password) 58 | $plain_text_password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($binary_string) 59 | $parameters.password = $plain_text_password 60 | 61 | # create the HTTP Basic Authorization header 62 | $pair = $parameters.username + ":" + $parameters.password 63 | $bytes = [System.Text.Encoding]::ASCII.GetBytes($pair) 64 | $base64 = [System.Convert]::ToBase64String($bytes) 65 | $basicAuthValue = "Basic $base64" 66 | 67 | # setup the request headers 68 | $parameters.headers = @{ 69 | 'Accept' = 'application/json' 70 | 'Authorization' = $basicAuthValue 71 | 'Content-Type' = 'application/json' 72 | } 73 | 74 | # disable SSL certification verification 75 | # you probably shouldn't do this in production ... 76 | if (-not ([System.Management.Automation.PSTypeName]'ServerCertificateValidationCallback').Type) 77 | { 78 | $certCallback = @" 79 | using System; 80 | using System.Net; 81 | using System.Net.Security; 82 | using System.Security.Cryptography.X509Certificates; 83 | public class ServerCertificateValidationCallback 84 | { 85 | public static void Ignore() 86 | { 87 | if(ServicePointManager.ServerCertificateValidationCallback ==null) 88 | { 89 | ServicePointManager.ServerCertificateValidationCallback += 90 | delegate 91 | ( 92 | Object obj, 93 | X509Certificate certificate, 94 | X509Chain chain, 95 | SslPolicyErrors errors 96 | ) 97 | { 98 | return true; 99 | }; 100 | } 101 | } 102 | } 103 | "@ 104 | Add-Type $certCallback 105 | } 106 | [ServerCertificateValidationCallback]::Ignore() 107 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 108 | 109 | # handle the exceptions 110 | try { 111 | # submit the request that has been constructed above 112 | # note that | Select * is not necessary and can be removed, 113 | # but does show how you can specify which JSON properties can 114 | # be extracted later 115 | Invoke-WebRequest ` 116 | -Uri $parameters.uri ` 117 | -Headers $parameters.headers ` 118 | -Method $parameters.method ` 119 | -Body $parameters.payload ` 120 | -TimeoutSec $parameters.timeout ` 121 | -UseBasicParsing ` 122 | -DisableKeepAlive ` 123 | | ConvertFrom-Json | Select * 124 | } 125 | # e.g. connections timeouts, missing required payload parameters, extra/unexpected payload parameters 126 | catch [System.Net.WebException] { 127 | Write-Host "An error occurred while processing the API request." 128 | Write-Host $_ 129 | } 130 | # e.g. attempting to use the GET verb on a request that should be POST 131 | catch [System.Net.ProtocolViolationException] { 132 | Write-Host "A payload/request body error occurred while making the request." 133 | Write-Host $_ 134 | } -------------------------------------------------------------------------------- /powershell/create_vm_v3_basic/readme.rst: -------------------------------------------------------------------------------- 1 | Nutanix Developer Portal Code Samples - create_vm_v3_basic.ps1 2 | ############################################################## 3 | 4 | This readme file is specifically for the **create_vm_v3_basic.ps1** PowerShell script. 5 | 6 | The setup instructions are the same as all other PowerShell scripts in this repository. This file is provided as additional/supplemental information for this specific code sample. 7 | 8 | Please see the `main `_ page for general instructions. 9 | 10 | Script Usage 11 | ............ 12 | 13 | Once you have configured your system to run these scripts (see link above), the script can be run as follows. 14 | 15 | #. Edit **create_vm_v3_basic.ps1** and edit the following link to match your Prism Central IP address. 16 | 17 | .. code-block:: powershell 18 | 19 | $parameters.cluster_ip = "10.0.0.1" 20 | 21 | #. Edit **create_vm_v3_basic.ps1** and edit the following variable to suit your requirements: 22 | 23 | .. code-block:: powershell 24 | 25 | $parameters.vm_name = "BasicVMViaAPIv3" 26 | 27 | #. Execute the script: 28 | 29 | .. code-block:: powershell 30 | 31 | create_vm_v3_basic.ps1 32 | 33 | #. Verify the script ran successfully and that the batch API request returned HTTP code 202: 34 | 35 | .. figure:: script_output.png 36 | 37 | #. If you prefer, you can also check Prism Central to ensure your VM was created successfully. -------------------------------------------------------------------------------- /powershell/create_vm_v3_basic/script_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/powershell/create_vm_v3_basic/script_output.png -------------------------------------------------------------------------------- /powershell/readme.rst: -------------------------------------------------------------------------------- 1 | Nutanix Developer Portal Code Samples - PowerShell 2 | ################################################## 3 | 4 | To use the PowerShell code samples, the following environment is recommended. 5 | 6 | - Windows PowerShell 5.1 or later 7 | - A suitable PowerShell editor, e.g. `Microsoft Visual Studio Code `_ or `Microsoft Visual Studio Community `_. Instructions for extending Visual Studio Code with PowerShell support are provided below. 8 | - An alternative editor, built into some versions of Windows, is **PowerShell ISE** 9 | - Access to a Nutanix Cluster for API testing purposes. 10 | - Nutanix Community Edition is supported but may not always provide the exact same APIs as a "full" Nutanix cluster. 11 | 12 | .. note:: Please note that instructions provided in this repository will assume the use of Visual Studio Code software. 13 | 14 | PowerShell Script Usage 15 | ....................... 16 | 17 | The provided PowerShell scripts are designed to be standalone and can be run without additional dependencies. 18 | 19 | The examples and screenshots below are from the **create_vm_v3_basic.ps1** sample. 20 | 21 | #. Open Windows PowerShell (administrative permissions are not required). 22 | #. Verify your PowerShell version by entering **$psversiontable** or **$PSVersionTable** (the variable is not case-sensitive) 23 | 24 | .. figure:: check_ps_version.png 25 | 26 | #. Select **View** > **Extensions**. 27 | #. In the search field, enter **PowerShell**. 28 | #. Install the **PowerShell** extension created by **Microsoft**. 29 | #. Using the selected code sample, create a new PowerShell file (extension **.ps1**, by default). 30 | #. Select the **$parameters.cluster_ip** variable with the correct IP address/FQDN of your cluster (the scripts will prompt for credentials). 31 | #. Click **Debug** > **Start Debugging**. 32 | #. The script will run and prompt for a username and password in the **Terminal** window. 33 | #. After entering credentials, and if the request was successful, the JSON response will show a status as shown below. 34 | 35 | .. figure:: script_output.png 36 | -------------------------------------------------------------------------------- /powershell/script_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/powershell/script_output.png -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | # Nutanix Developer Portal Code Samples - Python 2 | 3 | To use the Python code samples, the following environment is recommended. 4 | 5 | - Python >=3.7 (3.7 or later) 6 | - The accompanying JSON files from this repository (instructions and usage provided below). 7 | - A suitable Python editor, e.g. `Microsoft Visual Studio Code `_ for GUI editing. 8 | - Access to a Nutanix Cluster for testing Prism Element code samples (API v2.0) 9 | - Access to a Nutanix Prism Central instance for testing Prism Central code samples (API v4 and v4) 10 | 11 | ## Python Script Usage 12 | 13 | The provided Python scripts are designed to be standalone and can be run without additional dependencies beyond those provided above. 14 | 15 | The examples and screenshots below are from the **create_vm_v3_basic** sample. This sample uses **create_vm_v3_basic.json** for the request parameters. 16 | 17 | Note: These steps also assume you are copying/pasting code directly from the repository in the event that you haven't cloned the entire repository to your local machine. 18 | 19 | - Clone this repository 20 | - Create and activate a Python virtual environment: 21 | 22 | ``` 23 | python -m venv venv 24 | . venv/bin/activate 25 | ``` 26 | 27 | - If `requirements.txt` present, install dependencies: 28 | 29 | ``` 30 | pip install -r requirements.txt 31 | ``` 32 | 33 | - Edit `create_vm_v3_basic.json` and set appropriate values for your environment. 34 | - Run the script: 35 | 36 | ``` 37 | python create_vm_v3_basic.py create_vm_v3_basic.json 38 | ``` 39 | 40 | - The script will prompt for your account password, then submit the request based on the script spec. An example based on **create_vm_v3_basic.py** is shown below, running on Ubuntu 19.04. 41 | 42 | ![Screenshot of running create_vm_v3_basic.py](create_vm_v3_basic/screenshot.png) 43 | 44 | - Check the output to make sure the request has a state of **PENDING**. 45 | -------------------------------------------------------------------------------- /python/batch_request_simple/.gitignore: -------------------------------------------------------------------------------- 1 | venv/ 2 | *.json 3 | -------------------------------------------------------------------------------- /python/batch_request_simple/batch_request_simple.json: -------------------------------------------------------------------------------- 1 | { 2 | "cluster_ip": "10.0.0.0", 3 | "username": "admin", 4 | "batch_details":{ 5 | "action_on_failure": "CONTINUE", 6 | "execution_order": "SEQUENTIAL", 7 | "api_request_list": [ 8 | { 9 | "operation": "POST", 10 | "path_and_params": "/api/nutanix/v3/vms", 11 | "body": { 12 | "spec": { 13 | "name": "vm_from_batch", 14 | "resources": {} 15 | }, 16 | "metadata": { 17 | "kind": "vm" 18 | } 19 | } 20 | }, 21 | { 22 | "operation": "POST", 23 | "path_and_params": "/api/nutanix/v3/images", 24 | "body": { 25 | "spec": { 26 | "name": "image_from_batch", 27 | "resources": { 28 | "image_type": "DISK_IMAGE", 29 | "source_uri": "https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-1905.qcow2" 30 | }, 31 | "description": "Image created via v3 API batch request" 32 | }, 33 | "api_version": "3.1.0", 34 | "metadata": { 35 | "kind": "image", 36 | "categories": {}, 37 | "name": "image_from_batch" 38 | } 39 | } 40 | } 41 | ], 42 | "api_version": "3.0" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /python/batch_request_simple/batch_request_simple.json.sample: -------------------------------------------------------------------------------- 1 | { 2 | "cluster_ip": "10.0.0.1", 3 | "username": "admin", 4 | "batch_details":{ 5 | "action_on_failure": "CONTINUE", 6 | "execution_order": "SEQUENTIAL", 7 | "api_request_list": [ 8 | { 9 | "operation": "POST", 10 | "path_and_params": "/api/nutanix/v3/vms", 11 | "body": { 12 | "spec": { 13 | "name": "vm_from_batch", 14 | "resources": {} 15 | }, 16 | "metadata": { 17 | "kind": "vm" 18 | } 19 | } 20 | }, 21 | { 22 | "operation": "POST", 23 | "path_and_params": "/api/nutanix/v3/images", 24 | "body": { 25 | "spec": { 26 | "name": "image_from_batch", 27 | "resources": { 28 | "image_type": "DISK_IMAGE", 29 | "source_uri": "https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-1905.qcow2" 30 | }, 31 | "description": "Image created via v3 API batch request" 32 | }, 33 | "api_version": "3.1.0", 34 | "metadata": { 35 | "kind": "image", 36 | "categories": {}, 37 | "name": "image_from_batch" 38 | } 39 | } 40 | } 41 | ], 42 | "api_version": "3.0" 43 | } 44 | } -------------------------------------------------------------------------------- /python/batch_request_simple/batch_request_simple.py: -------------------------------------------------------------------------------- 1 | ''' 2 | use the Prism REST API v3 to combine multiple requests 3 | into a single batch via POST 4 | ''' 5 | 6 | import requests 7 | import urllib3 8 | import argparse 9 | import getpass 10 | import json 11 | from base64 import b64encode 12 | import sys 13 | import os 14 | 15 | ''' 16 | suppress warnings about insecure connections 17 | you probably shouldn't do this in production 18 | ''' 19 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 20 | 21 | ''' 22 | setup our command line parameters 23 | for this example we only require the a single parameter 24 | - the name of the JSON file that contains our request parameters 25 | this is a very clean way of passing parameters to this sort of 26 | script, without the need for excessive parameters on the command line 27 | ''' 28 | parser = argparse.ArgumentParser() 29 | parser.add_argument('json', 30 | help='JSON file containing query parameters') 31 | args = parser.parse_args() 32 | 33 | ''' 34 | try and read the JSON parameters from the supplied file 35 | ''' 36 | json_data = '' 37 | try: 38 | script_dir = os.path.dirname(os.path.realpath(__file__)) 39 | with open(f'{script_dir}/{args.json}', 'r') as params: 40 | json_data = json.load(params) 41 | except FileNotFoundError: 42 | print(f'{args.json} parameters file not found.') 43 | sys.exit() 44 | except json.decoder.JSONDecodeError: 45 | print(f'{args.json} does not appear to contain valid JSON. \ 46 | Please check the file and try again.') 47 | sys.exit() 48 | 49 | # get the cluster password 50 | cluster_password = getpass.getpass(prompt='Please enter your cluster \ 51 | password: ', stream=None) 52 | 53 | try: 54 | 55 | ''' 56 | setup the HTTP Basic Authorization header based on the 57 | supplied username and password 58 | done this way so that passwords are not supplied on the command line 59 | ''' 60 | encoded_credentials = b64encode(bytes( 61 | f'{json_data["username"]}:{cluster_password}', 62 | encoding='ascii')).decode('ascii') 63 | auth_header = f'Basic {encoded_credentials}' 64 | 65 | # setup the URL that will be used for the API request 66 | url = f'https://{json_data["cluster_ip"]}:9440/api/nutanix/v3/batch' 67 | 68 | # setup the JSON payload that will be used for this request 69 | payload = json.dumps(json_data['batch_details']) 70 | 71 | ''' 72 | setup the request headers 73 | note the use of {auth_header} i.e. the Basic Authorization 74 | credentials we setup earlier 75 | ''' 76 | headers = { 77 | 'Accept': "application/json", 78 | 'Content-Type': "application/json", 79 | 'Authorization': f"{auth_header}", 80 | 'cache-control': "no-cache" 81 | } 82 | 83 | # submit the request 84 | try: 85 | response = requests.request("POST", url, data=payload, headers=headers, 86 | verify=False) 87 | 88 | if(response.ok): 89 | print(response.text) 90 | else: 91 | print(f'An error occurred while connecting to {json_data["cluster_ip"]}.') 92 | ''' 93 | the following line can be uncommented to show 94 | detailed error information 95 | ''' 96 | print(response.text) 97 | except Exception as ex: 98 | print(f'An {type(ex).__name__} exception occurred while \ 99 | connecting to {json_data["cluster_ip"]}.\nArgument: {ex.args}.') 100 | 101 | except KeyError: 102 | print(f'{args.json} file does not appear to contain the required \ 103 | fields. Please check the file and try again.') 104 | 105 | ''' 106 | wait for the enter key before continuing 107 | this is to prevent terminal flashing if being run inside VS Code, for example 108 | ''' 109 | input('Press ENTER to exit.') 110 | -------------------------------------------------------------------------------- /python/batch_request_simple/readme.rst: -------------------------------------------------------------------------------- 1 | Python Code Samples - batch_request_simple.py 2 | ############################################# 3 | 4 | This readme file is specifically for the **batch_request_simple.py** Python code sample. 5 | 6 | The setup instructions are the same as all other python code samples in this repository. This file is provided as additional/supplemental information for this specific code sample. 7 | 8 | Please see the `main `_ page for general instructions. 9 | 10 | **Usage instructions are shown at the bottom of this page.** 11 | 12 | Code Sample Details 13 | ................... 14 | 15 | A quick intro, first. The **batch_request_simple.py** code sample shows a basic demo of REST API batch requests with Python 3. The expectation is that users wanting to run several request at the same time. For example: 16 | 17 | - Multiple VMs needing the same change 18 | - Sequential requests that relate to one another (although they don't need to, at all) 19 | 20 | **batch_request_simple.py** has been provided for demo purposes and should only be used with the following provisions in mind: 21 | 22 | - A single batch should not contain no more than 60 individual requests 23 | - Additional exception handling should be added before using this in production 24 | 25 | JSON Parameters file 26 | .................... 27 | 28 | A sample parameters file has been provided with this script. It contains variables for: 29 | 30 | - Prism Central IP address 31 | - Prism Central username 32 | - The POST payload to be used with the **batch** request. In a 'real world' situation you could update this sample payload to carry out the requests you require. 33 | 34 | Usage 35 | ----- 36 | 37 | It is strongly recommended to read the more detailed explanation of using batch requests as been outlined here: `Batch Brewing – Multiple Requests with the Nutanix APIs `_. 38 | 39 | .. code-block:: bash 40 | 41 | usage: batch_request_simple.py [-h] json 42 | 43 | positional arguments: 44 | json JSON file containing query parameters 45 | 46 | optional arguments: 47 | -h, --help show this help message and exit 48 | 49 | Example: 50 | 51 | .. code-block:: bash 52 | 53 | /usr/bin/python3.8 ./batch_request_simple.py batch_request_simple.json 54 | -------------------------------------------------------------------------------- /python/create_image_v2.0/create_image_v2.0.json: -------------------------------------------------------------------------------- 1 | {"cluster_ip":"10.0.0.1","username":"admin","ctr_name":"container1","ctr_uuid":"00000000-0000-0000-0000-000000000000","iso_url":"http://centos.melbourneitmirror.net/8.1.1911/isos/x86_64/CentOS-8.1.1911-x86_64-dvd1.iso","image_name":"CentOS8_DVD","image_annotation":"CentOS 8 DVD image created with Prism REST API v2.0"} -------------------------------------------------------------------------------- /python/create_image_v2.0/create_image_v2.0.py: -------------------------------------------------------------------------------- 1 | ''' 2 | use the Prism REST API v2.0 to create an Image Services image 3 | without modification, the script will create an image sourced from any HTTP-accessible URL 4 | ''' 5 | 6 | import requests 7 | import urllib3 8 | import argparse 9 | import getpass 10 | import json 11 | from base64 import b64encode 12 | import sys 13 | import os 14 | 15 | ''' 16 | suppress warnings about insecure connections 17 | you probably shouldn't do this in production 18 | ''' 19 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 20 | 21 | ''' 22 | setup our command line parameters 23 | for this example we only require the a single parameter - the name of the JSON file that contains our request parameters 24 | this is a very clean way of passing parameters to this sort of script, without the need for excessive parameters on the command line 25 | ''' 26 | parser = argparse.ArgumentParser() 27 | parser.add_argument('json', 28 | help='JSON file containing query parameters') 29 | args = parser.parse_args() 30 | 31 | ''' 32 | try and read the JSON parameters from the supplied file 33 | ''' 34 | json_data = '' 35 | try: 36 | script_dir = os.path.dirname(os.path.realpath(__file__)) 37 | with open(f'{script_dir}/{args.json}', 'r') as params: 38 | json_data = json.load(params) 39 | except FileNotFoundError: 40 | print(f'{args.json} parameters file not found.') 41 | sys.exit() 42 | except json.decoder.JSONDecodeError: 43 | print(f'{args.json} does not appear to contain valid JSON. Please check the file and try again.') 44 | sys.exit() 45 | 46 | # get the cluster password 47 | cluster_password = getpass.getpass(prompt='Please enter your cluster password: ',stream=None) 48 | 49 | try: 50 | 51 | ''' 52 | setup the HTTP Basic Authorization header based on the supplied username and password 53 | done this way so that passwords are not supplied on the command line 54 | ''' 55 | encoded_credentials = b64encode(bytes(f"{json_data['username']}:{cluster_password}", 56 | encoding="ascii")).decode("ascii") 57 | auth_header = f'Basic {encoded_credentials}' 58 | 59 | # setup the URL that will be used for the API request 60 | url = f"https://{json_data['cluster_ip']}:9440/api/nutanix/v2.0/images" 61 | 62 | # setup the JSON payload that will be used for this request 63 | payload = f'{{ \ 64 | "annotation":"{json_data["""image_annotation"""]}", \ 65 | "image_import_spec":{{ \ 66 | "storage_container_name":"{json_data["""ctr_name"""]}", \ 67 | "storage_container_uuid":"{json_data["""ctr_uuid"""]}", \ 68 | "url":"{json_data["""iso_url"""]}" \ 69 | }}, \ 70 | "image_type":"ISO_IMAGE", \ 71 | "name":"{json_data["""image_name"""]}" \ 72 | }}' 73 | 74 | ''' 75 | setup the request headers 76 | note the use of {auth_header} i.e. the Basic Authorization credentials we setup earlier 77 | ''' 78 | headers = { 79 | 'Accept': "application/json", 80 | 'Content-Type': "application/json", 81 | 'Authorization': f"{auth_header}", 82 | 'cache-control': "no-cache" 83 | } 84 | 85 | # submit the request 86 | try: 87 | response = requests.request("POST", url, data=payload, headers=headers, 88 | verify=False) 89 | if(response.ok): 90 | print(response.text) 91 | else: 92 | print(f'An error occurred while connecting to {json_data["cluster_ip"]}.') 93 | # the following line can be uncommented to show detailed error information 94 | # print(response.text) 95 | except Exception as ex: 96 | print(f'An {type(ex).__name__} exception occurred while connecting to {json_data["cluster_ip"]}.\nArgument: {ex.args}.') 97 | 98 | except KeyError: 99 | print(f'{args.json} file does not appear to contain the required fields. Please check the file and try again.') -------------------------------------------------------------------------------- /python/create_image_v2.0/readme.rst: -------------------------------------------------------------------------------- 1 | ######################################## 2 | Create Image with v2.0 Prism Element API 3 | ######################################## 4 | 5 | Python script to connect to Prism Element and use the v2.0 APIs to create a disk image. 6 | 7 | ********** 8 | Disclaimer 9 | ********** 10 | 11 | This is **not** a production-grade script. Please make sure you add appropriate exception handling and error-checking before running it in production. See note re versions below, too. 12 | 13 | ****** 14 | Author 15 | ****** 16 | 17 | Chris Rasmussen, Developer Content Architect, Nutanix (Melbourne, AU) 18 | 19 | ********* 20 | Changelog 21 | ********* 22 | 23 | - 2020.02.26 - Code sample reorganised into individual folder 24 | - 2019.07.23 - Code sample created 25 | 26 | ******* 27 | Details 28 | ******* 29 | 30 | Connect to Prism Element and use the v2.0 APIs to create a disk image. 31 | 32 | Requires create_image_v2.0.json to be populated with the following information: 33 | 34 | - **cluster_ip**: Prism Element IP address 35 | - **username**: The username for your Prism Element instance 36 | - **ctr_name**: The name of the container that will store the new image 37 | - **ctr_uuid**: The UUID of the container that will store the new image 38 | - **iso_url**: The full URL for the ISO file to use when creating the image 39 | - **image_name**: The name for the new image (this will appear in image lists) 40 | - **image_annotation**: A meaningful description for the new image 41 | 42 | Example v2.0 API **GET** request to get container information: 43 | 44 | .. code-block:: bash 45 | 46 | https://cluster_ip:9440/api/nutanix/v2.0/storage_containers 47 | 48 | 49 | ***** 50 | Usage 51 | ***** 52 | 53 | Virtual Environment 54 | =================== 55 | 56 | All the steps below assume you have a terminal session running with the current directory set to the location of the script. 57 | 58 | - It is strongly recommended to run development scripts like this within a virtual environment. For example, if using Python 3.7 on Linux: 59 | 60 | .. code-block:: bash 61 | 62 | python3.7 -m venv venv 63 | . venv/bin/activate 64 | 65 | - Install dependencies: 66 | 67 | .. code-block:: bash 68 | 69 | pip3 install -e . 70 | 71 | - Edit **create_image_v2.0.json** to match your environment 72 | 73 | Script Command Line 74 | =================== 75 | 76 | .. code-block:: bash 77 | 78 | python3.7 create_image_v2.0.py --help 79 | 80 | Generates: 81 | 82 | .. code-block:: bash 83 | 84 | usage: create_image_v2.0.py [-h] json 85 | 86 | positional arguments: 87 | json JSON file containing query parameters 88 | 89 | optional arguments: 90 | -h, --help show this help message and exit 91 | 92 | ***** 93 | Notes 94 | ***** 95 | 96 | - High-level testing has been carried out on Prism Element version 5.12 97 | - Other versions may produce unpredictable results 98 | - The installation of specific Python versions, pip3 etc are beyond the scope of this readme 99 | 100 | ******* 101 | Example 102 | ******* 103 | 104 | A complete command-line example is shown below: 105 | 106 | .. code-block:: bash 107 | 108 | python3.7 create_image_v2.0.py create_image_v2.0.json 109 | 110 | ********** 111 | Screenshot 112 | ********** 113 | 114 | This is what the script looks like as it is run. This screenshot is the output of the example command above. 115 | 116 | .. figure:: screenshot.png 117 | 118 | ******* 119 | Support 120 | ******* 121 | 122 | These scripts are *unofficial* and are not supported or maintained by Nutanix in any way. 123 | 124 | In addition, please also be advised that these scripts may run and operate in ways that do not follow best practices. Please check through each script to ensure it meets your requirements. 125 | 126 | **Changes will be required before these scripts can be used in production environments.** -------------------------------------------------------------------------------- /python/create_image_v2.0/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/create_image_v2.0/screenshot.png -------------------------------------------------------------------------------- /python/create_image_v2.0/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | with open('readme.rst', encoding='UTF-8') as f: 4 | readme = f.read() 5 | 6 | setup( 7 | name='create-image-v2.0', 8 | version='1.1', 9 | description='Use the Prism Element v2.0 API to create a disk image.', 10 | long_description=readme, 11 | author='Chris Rasmussen', 12 | author_email='crasmussen@nutanix.com', 13 | install_requires=[ 14 | 'requests', 15 | 'urllib3' 16 | ], 17 | packages=find_packages('.'), 18 | package_dir={'': '.'} 19 | ) -------------------------------------------------------------------------------- /python/create_vm_v3_basic/create_vm_v3_basic.json: -------------------------------------------------------------------------------- 1 | {"pc_ip":"10.0.0.1","username":"admin","vm_name":"BasicVMViaAPIv3","cluster_name":"cluster_name_here","cluster_uuid":"00000000-0000-0000-0000-000000000000"} -------------------------------------------------------------------------------- /python/create_vm_v3_basic/create_vm_v3_basic.py: -------------------------------------------------------------------------------- 1 | ''' 2 | use the Prism REST API v3 to create a simple VM 3 | ''' 4 | 5 | import requests 6 | import urllib3 7 | import argparse 8 | import getpass 9 | import json 10 | from base64 import b64encode 11 | import sys 12 | import os 13 | 14 | ''' 15 | suppress warnings about insecure connections 16 | you probably shouldn't do this in production 17 | ''' 18 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 19 | 20 | ''' 21 | setup our command line parameters 22 | for this example we only require the a single parameter 23 | - the name of the JSON file that contains our request parameters 24 | this is a very clean way of passing parameters to this sort of 25 | script, without the need for excessive parameters on the command line 26 | ''' 27 | parser = argparse.ArgumentParser() 28 | parser.add_argument('json', 29 | help='JSON file containing query parameters') 30 | args = parser.parse_args() 31 | 32 | ''' 33 | try and read the JSON parameters from the supplied file 34 | ''' 35 | json_data = '' 36 | try: 37 | script_dir = os.path.dirname(os.path.realpath(__file__)) 38 | with open(f'{script_dir}/{args.json}', 'r') as params: 39 | json_data = json.load(params) 40 | except FileNotFoundError: 41 | print(f'{args.json} parameters file not found.') 42 | sys.exit() 43 | except json.decoder.JSONDecodeError: 44 | print(f'{args.json} does not appear to contain valid JSON. \ 45 | Please check the file and try again.') 46 | sys.exit() 47 | 48 | # get the cluster password 49 | cluster_password = getpass.getpass(prompt='Please enter your cluster \ 50 | password: ', stream=None) 51 | 52 | try: 53 | 54 | ''' 55 | setup the HTTP Basic Authorization header based on the 56 | supplied username and password 57 | done this way so that passwords are not supplied on the command line 58 | ''' 59 | encoded_credentials = b64encode(bytes( 60 | f'{json_data["username"]}:{cluster_password}', 61 | encoding='ascii')).decode('ascii') 62 | auth_header = f'Basic {encoded_credentials}' 63 | 64 | # setup the URL that will be used for the API request 65 | url = f'https://{json_data["pc_ip"]}:9440/api/nutanix/v3/vms' 66 | 67 | # setup the JSON payload that will be used for this request 68 | payload = f'{{ \ 69 | "spec":{{ \ 70 | "name":"{json_data["""vm_name"""]}", \ 71 | "resources":{{ \ 72 | }}, \ 73 | "cluster_reference":{{ \ 74 | "kind":"cluster", \ 75 | "name":"{json_data["""cluster_name"""]}", \ 76 | "uuid":"{json_data["""cluster_uuid"""]}" \ 77 | }}\ 78 | }}, \ 79 | "metadata":{{ \ 80 | "kind":"vm" \ 81 | }} \ 82 | }}' 83 | 84 | ''' 85 | setup the request headers 86 | note the use of {auth_header} i.e. the Basic Authorization 87 | credentials we setup earlier 88 | ''' 89 | headers = { 90 | 'Accept': "application/json", 91 | 'Content-Type': "application/json", 92 | 'Authorization': f"{auth_header}", 93 | 'cache-control': "no-cache" 94 | } 95 | 96 | # submit the request 97 | try: 98 | response = requests.request("POST", url, data=payload, headers=headers, 99 | verify=False) 100 | if(response.ok): 101 | print(response.text) 102 | else: 103 | print(f'An error occurred while connecting to {json_data["pc_ip"]}.') 104 | ''' 105 | the following line can be uncommented to show 106 | detailed error information 107 | ''' 108 | print(response.text) 109 | except Exception as ex: 110 | print(f'An {type(ex).__name__} exception occurred while \ 111 | connecting to {json_data["pc_ip"]}.\nArgument: {ex.args}.') 112 | 113 | except KeyError: 114 | print(f'{args.json} file does not appear to contain the required \ 115 | fields. Please check the file and try again.') 116 | 117 | ''' 118 | wait for the enter key before continuing 119 | this is to prevent terminal flashing if being run inside VS Code, for example 120 | ''' 121 | input('Press ENTER to exit.') 122 | -------------------------------------------------------------------------------- /python/create_vm_v3_basic/readme.rst: -------------------------------------------------------------------------------- 1 | ###################### 2 | Create Basic API v3 VM 3 | ###################### 4 | 5 | Python script to connect to Prism Central and use the v3 APIs to create a VM with basic specs. 6 | 7 | ********** 8 | Disclaimer 9 | ********** 10 | 11 | This is **not** a production-grade script. Please make sure you add appropriate exception handling and error-checking before running it in production. See note re versions below, too. 12 | 13 | ****** 14 | Author 15 | ****** 16 | 17 | Chris Rasmussen, Developer Content Architect, Nutanix (Melbourne, AU) 18 | 19 | ********* 20 | Changelog 21 | ********* 22 | 23 | - 2020.02.20 - Code sample updated to deal with "missing cluster reference" case 24 | - 2019.07.23 - Code sample created 25 | 26 | ******* 27 | Details 28 | ******* 29 | 30 | Connect to Prism Central and use the v3 APIs to create a VM with basic specs. 31 | 32 | Requires create_vm_v3_basic.json to be populated with the following information: 33 | 34 | - **pc_ip**: Prism Central IP address 35 | - **username**: Prism Central username 36 | - **vm_name**: The name of the VM to create 37 | - **cluster_name**: The name of the cluster to create the VM on 38 | - **cluster_uuid**: The UUID of the cluster to create the VM on 39 | 40 | Note re cluster UUID - This is required to deal with the use case where the specified Prism Central instance has multiple connected clusters (quite common in the real world). 41 | 42 | Example API **POST** request to get the cluster UUID: 43 | 44 | .. code-block:: bash 45 | 46 | https://pc_ip:9440/api/nutanix/v3/clusters/list 47 | 48 | Body to use with the request above: 49 | 50 | .. code-block:: json 51 | 52 | {"kind":"cluster"} 53 | 54 | 55 | ***** 56 | Usage 57 | ***** 58 | 59 | Virtual Environment 60 | =================== 61 | 62 | All the steps below assume you have a terminal session running with the current directory set to the location of the script. 63 | 64 | - It is strongly recommended to run development scripts like this within a virtual environment. For example, if using Python 3.7 on Linux: 65 | 66 | .. code-block:: bash 67 | 68 | python3.7 -m venv venv 69 | . venv/bin/activate 70 | 71 | - Install dependencies: 72 | 73 | .. code-block:: bash 74 | 75 | pip3 install -e . 76 | 77 | - Edit **create_vm_v3_basic.json** to match your environment 78 | 79 | Script Command Line 80 | =================== 81 | 82 | .. code-block:: bash 83 | 84 | python3.7 create_vm_v3_basic.py create_vm_v3_basic.json --help 85 | 86 | Generates: 87 | 88 | .. code-block:: bash 89 | 90 | usage: create_vm_v3_basic.py [-h] json 91 | 92 | positional arguments: 93 | json JSON file containing query parameters 94 | 95 | optional arguments: 96 | -h, --help show this help message and exit 97 | 98 | ***** 99 | Notes 100 | ***** 101 | 102 | - High-level testing has been carried out on Prism Central version 5.11 103 | - Other versions may produce unpredictable results 104 | - The installation of specific Python versions, pip3 etc are beyond the scope of this readme 105 | 106 | ******* 107 | Example 108 | ******* 109 | 110 | A complete command-line example is shown below: 111 | 112 | .. code-block:: bash 113 | 114 | python3.7 create_vm_v3_basic.py create_vm_v3_basic.json 115 | 116 | ********** 117 | Screenshot 118 | ********** 119 | 120 | This is what the script looks like as it is run. This screenshot is the output of the example command above. 121 | 122 | .. figure:: screenshot.png 123 | 124 | ******* 125 | Support 126 | ******* 127 | 128 | These scripts are *unofficial* and are not supported or maintained by Nutanix in any way. 129 | 130 | In addition, please also be advised that these scripts may run and operate in ways that do not follow best practices. Please check through each script to ensure it meets your requirements. 131 | 132 | **Changes will be required before these scripts can be used in production environments.** -------------------------------------------------------------------------------- /python/create_vm_v3_basic/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/create_vm_v3_basic/screenshot.png -------------------------------------------------------------------------------- /python/create_vm_v3_basic/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | with open('readme.rst', encoding='UTF-8') as f: 4 | readme = f.read() 5 | 6 | setup( 7 | name='create-basic-vm', 8 | version='1.1', 9 | description='Use the Prism Central API to create a basic Virtual Machine.', 10 | long_description=readme, 11 | author='Chris Rasmussen', 12 | author_email='crasmussen@nutanix.com', 13 | install_requires=[ 14 | 'requests', 15 | 'urllib3' 16 | ], 17 | packages=find_packages('.'), 18 | package_dir={'': '.'} 19 | ) -------------------------------------------------------------------------------- /python/create_vm_v3_detailed/create_vm_v3_detailed.json: -------------------------------------------------------------------------------- 1 | {"cluster_ip":"10.0.0.1","username":"admin","vm_name":"DetailedVMViaAPIv3","cluster_name":"cluster_name_here","cluster_uuid":"00000000-0000-0000-0000-000000000000","vcpus_per_socket":1,"num_sockets":1,"memory_size_mib":1024,"first_disk_size_mib":1024,"first_nic_subnet_name":"subnet_name_here","first_nic_subnet_uuid":"00000000-0000-0000-0000-000000000000"} -------------------------------------------------------------------------------- /python/create_vm_v3_detailed/create_vm_v3_detailed.py: -------------------------------------------------------------------------------- 1 | ''' 2 | use the Prism REST API v3 to create a detailed VM 3 | configures VM with most commonly-required fields 4 | ''' 5 | 6 | import requests 7 | import urllib3 8 | import argparse 9 | import getpass 10 | import json 11 | from base64 import b64encode 12 | import sys 13 | import os 14 | 15 | ''' 16 | suppress warnings about insecure connections 17 | you probably shouldn't do this in production 18 | ''' 19 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 20 | 21 | ''' 22 | setup our command line parameters 23 | for this example we only require the a single parameter - the name of the JSON file that contains our request parameters 24 | this is a very clean way of passing parameters to this sort of script, without the need for excessive parameters on the command line 25 | ''' 26 | parser = argparse.ArgumentParser() 27 | parser.add_argument('json', 28 | help='JSON file containing query parameters') 29 | args = parser.parse_args() 30 | 31 | ''' 32 | try and read the JSON parameters from the supplied file 33 | ''' 34 | json_data = '' 35 | try: 36 | script_dir = os.path.dirname(os.path.realpath(__file__)) 37 | with open(f'{script_dir}/{args.json}', 'r') as params: 38 | json_data = json.load(params) 39 | except FileNotFoundError: 40 | print(f'{args.json} parameters file not found.') 41 | sys.exit() 42 | except json.decoder.JSONDecodeError: 43 | print(f'{args.json} does not appear to contain valid JSON. Please check the file and try again.') 44 | sys.exit() 45 | 46 | # get the cluster password 47 | cluster_password = getpass.getpass(prompt='Please enter your cluster password: ',stream=None) 48 | 49 | try: 50 | 51 | ''' 52 | setup the HTTP Basic Authorization header based on the supplied username and password 53 | done this way so that passwords are not supplied on the command line 54 | ''' 55 | encoded_credentials = b64encode(bytes(f"{json_data['username']}:{cluster_password}", 56 | encoding="ascii")).decode("ascii") 57 | auth_header = f'Basic {encoded_credentials}' 58 | 59 | # setup the URL that will be used for the API request 60 | url = f"https://{json_data['cluster_ip']}:9440/api/nutanix/v3/vms" 61 | 62 | # setup the JSON payload that will be used for this request 63 | payload = f'{{ \ 64 | "spec":{{ \ 65 | "name":"{json_data["""vm_name"""]}", \ 66 | "resources":{{ \ 67 | "power_state":"ON", \ 68 | "num_vcpus_per_socket":{json_data["""vcpus_per_socket"""]}, \ 69 | "num_sockets":{json_data["""num_sockets"""]}, \ 70 | "memory_size_mib":{json_data["""memory_size_mib"""]}, \ 71 | "disk_list":[{{ \ 72 | "disk_size_mib":{json_data["""first_disk_size_mib"""]}, \ 73 | "device_properties":{{ \ 74 | "device_type":"DISK" \ 75 | }} \ 76 | }}, \ 77 | {{ \ 78 | "device_properties":{{ \ 79 | "device_type":"CDROM" \ 80 | }} \ 81 | }}], \ 82 | "nic_list":[{{ \ 83 | "nic_type":"NORMAL_NIC", \ 84 | "is_connected":true, \ 85 | "ip_endpoint_list":[{{ \ 86 | "ip_type":"DHCP" \ 87 | }}], \ 88 | "subnet_reference":{{ \ 89 | "kind":"subnet", \ 90 | "name":"{json_data["""first_nic_subnet_name"""]}", \ 91 | "uuid":"{json_data["""first_nic_subnet_uuid"""]}" \ 92 | }} \ 93 | }}], \ 94 | "guest_tools":{{ \ 95 | "nutanix_guest_tools":{{ \ 96 | "state":"ENABLED", \ 97 | "iso_mount_state":"MOUNTED" \ 98 | }} \ 99 | }} \ 100 | }}, \ 101 | "cluster_reference":{{ \ 102 | "kind":"cluster", \ 103 | "name":"{json_data["""cluster_name"""]}", \ 104 | "uuid":"{json_data["""cluster_uuid"""]}" \ 105 | }} \ 106 | }}, \ 107 | "api_version":"3.1.0", \ 108 | "metadata":{{ \ 109 | "kind":"vm" \ 110 | }} \ 111 | }}' 112 | 113 | ''' 114 | setup the request headers 115 | note the use of {auth_header} i.e. the Basic Authorization credentials we setup earlier 116 | ''' 117 | headers = { 118 | 'Accept': "application/json", 119 | 'Content-Type': "application/json", 120 | 'Authorization': f"{auth_header}", 121 | 'cache-control': "no-cache" 122 | } 123 | 124 | # submit the request 125 | try: 126 | response = requests.request("POST", url, data=payload, headers=headers, 127 | verify=False, 128 | timeout=1) 129 | if(response.ok): 130 | print(response.text) 131 | else: 132 | print(f'An error occurred while connecting to {json_data["cluster_ip"]}.') 133 | # the following line can be uncommented to show detailed error information 134 | # print(response.text) 135 | except Exception as ex: 136 | print(f'An {type(ex).__name__} exception occurred while connecting to {json_data["cluster_ip"]}.\nArgument: {ex.args}.') 137 | 138 | except KeyError: 139 | print(f'{args.json} file does not appear to contain the required fields. Please check the file and try again.') 140 | 141 | ''' 142 | wait for the enter key before continuing 143 | this is to prevent terminal flashing if being run inside VS Code, for example 144 | ''' 145 | input('Press ENTER to exit.') 146 | -------------------------------------------------------------------------------- /python/create_vm_v3_detailed/readme.rst: -------------------------------------------------------------------------------- 1 | ######################### 2 | Create Detailed API v3 VM 3 | ######################### 4 | 5 | Python script to connect to Prism Central and use the v3 APIs to create a VM with detailed specs. 6 | 7 | Unlike the basic example also available in this repository, this sample creates a virtual machine with attached disk and network adapter. 8 | 9 | ********** 10 | Disclaimer 11 | ********** 12 | 13 | This is **not** a production-grade script. Please make sure you add appropriate exception handling and error-checking before running it in production. See note re versions below, too. 14 | 15 | ****** 16 | Author 17 | ****** 18 | 19 | Chris Rasmussen, Developer Content Architect, Nutanix (Melbourne, AU) 20 | 21 | ********* 22 | Changelog 23 | ********* 24 | 25 | - 2020.02.20 - Code sample updated to deal with "missing cluster reference" case 26 | - 2019.07.23 - Code sample created 27 | 28 | ******* 29 | Details 30 | ******* 31 | 32 | Connect to Prism Central and use the v3 APIs to create a VM with detailed specs. 33 | 34 | Requires create_vm_v3_detailed.json to be populated with the following information: 35 | 36 | - **pc_ip**: Prism Central IP address 37 | - **username**: Prism Central username 38 | - **vm_name**: The name of the VM to create 39 | - **cluster_name**: The name of the cluster to create the VM on 40 | - **cluster_uuid**: The UUID of the cluster to create the VM on 41 | - **vcpus_per_socket**: The number of vCPUs per socket to assign to the new VM 42 | - **num_sockets**: The number of sockets to assign to the new VM 43 | - **memory_size_mib**: The memory size in MiB to assign to the new VM 44 | - **first_disk_size_mib**: The size of the first disk in MiB to assign to the new VM 45 | - **first_nic_subnet_name**: The name of the VM's first NIC's network/subnet 46 | - **first_nic_subnet_uuid**: The UUID of the VM's first NIC's network/subnet 47 | 48 | Note re cluster UUID - This is required to deal with the use case where the specified Prism Central instance has multiple connected clusters (quite common in the real world). 49 | 50 | Example API **POST** request to get the cluster UUID: 51 | 52 | .. code-block:: bash 53 | 54 | https://pc_ip:9440/api/nutanix/v3/clusters/list 55 | 56 | Body to use with the request above: 57 | 58 | .. code-block:: json 59 | 60 | {"kind":"cluster"} 61 | 62 | Note re subnet UUID - This is required when creating attached VM NICs. 63 | 64 | Example API **POST** request to get the subnet UUID: 65 | 66 | .. code-block:: bash 67 | 68 | https://pc_ip:9440/api/nutanix/v3/subnets/list 69 | 70 | Body to use with the request above: 71 | 72 | .. code-block:: json 73 | 74 | {"kind":"subnet"} 75 | 76 | 77 | ***** 78 | Usage 79 | ***** 80 | 81 | Virtual Environment 82 | =================== 83 | 84 | All the steps below assume you have a terminal session running with the current directory set to the location of the script. 85 | 86 | - It is strongly recommended to run development scripts like this within a virtual environment. For example, if using Python 3.7 on Linux: 87 | 88 | .. code-block:: bash 89 | 90 | python3.7 -m venv venv 91 | . venv/bin/activate 92 | 93 | - Install dependencies: 94 | 95 | .. code-block:: bash 96 | 97 | pip3 install -e . 98 | 99 | - Edit **create_vm_v3_detailed.json** to match your environment 100 | 101 | Script Command Line 102 | =================== 103 | 104 | .. code-block:: bash 105 | 106 | python3.7 create_vm_v3_detailed.py create_vm_v3_detailed.json --help 107 | 108 | Generates: 109 | 110 | .. code-block:: bash 111 | 112 | usage: create_vm_v3_detailed.py [-h] json 113 | 114 | positional arguments: 115 | json JSON file containing query parameters 116 | 117 | optional arguments: 118 | -h, --help show this help message and exit 119 | 120 | ***** 121 | Notes 122 | ***** 123 | 124 | - High-level testing has been carried out on Prism Central version 5.11 125 | - Other versions may produce unpredictable results 126 | - The installation of specific Python versions, pip3 etc are beyond the scope of this readme 127 | 128 | ******* 129 | Example 130 | ******* 131 | 132 | A complete command-line example is shown below: 133 | 134 | .. code-block:: bash 135 | 136 | python3.7 create_vm_v3_detailed.py create_vm_v3_detailed.json 137 | 138 | ********** 139 | Screenshot 140 | ********** 141 | 142 | This is what the script looks like as it is run. This screenshot is the output of the example command above. 143 | 144 | .. figure:: screenshot.png 145 | 146 | ******* 147 | Support 148 | ******* 149 | 150 | These scripts are *unofficial* and are not supported or maintained by Nutanix in any way. 151 | 152 | In addition, please also be advised that these scripts may run and operate in ways that do not follow best practices. Please check through each script to ensure it meets your requirements. 153 | 154 | **Changes will be required before these scripts can be used in production environments.** -------------------------------------------------------------------------------- /python/create_vm_v3_detailed/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | with open('readme.rst', encoding='UTF-8') as f: 4 | readme = f.read() 5 | 6 | setup( 7 | name='create-detailed-vm', 8 | version='1.1', 9 | description='Use the Prism Central API to create a detailed Virtual Machine.', 10 | long_description=readme, 11 | author='Chris Rasmussen', 12 | author_email='crasmussen@nutanix.com', 13 | install_requires=[ 14 | 'requests', 15 | 'urllib3' 16 | ], 17 | packages=find_packages('.'), 18 | package_dir={'': '.'} 19 | ) -------------------------------------------------------------------------------- /python/get_cluster_info_v3/.gitignore: -------------------------------------------------------------------------------- 1 | venv/ 2 | *.html 3 | -------------------------------------------------------------------------------- /python/get_cluster_info_v3/requirements.txt: -------------------------------------------------------------------------------- 1 | urllib3==2.2.2 2 | requests==2.32.3 3 | -------------------------------------------------------------------------------- /python/get_cluster_info_v3/screenshot_html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/get_cluster_info_v3/screenshot_html.png -------------------------------------------------------------------------------- /python/get_cluster_info_v3/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | with open('readme.rst', encoding='UTF-8') as f: 4 | readme = f.read() 5 | 6 | setup( 7 | name='nutanix-cluster-info', 8 | version='3.1', 9 | description='Use the Prism Central API to get Nutanix environment info, then generate an HTML report from it.', 10 | long_description=readme, 11 | author='Chris Rasmussen', 12 | author_email='crasmussen@nutanix.com', 13 | install_requires=[ 14 | 'requests', 15 | 'urllib3' 16 | ], 17 | packages=find_packages('.'), 18 | package_dir={'': '.'} 19 | ) 20 | -------------------------------------------------------------------------------- /python/get_cluster_info_v3/templates/nutanixv3.html.example: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Prism Central Details (API v3) 7 | 8 | 9 | 13 | 14 | 15 | 16 | 17 |
18 | 19 |

The Prism Central information shown in this page is intended for demo purposes only.

20 |

Please be aware that the totals shown in parentheses next to each entity type are accurate for each entity type, but includes deleted entities. This is particularly applicable to entities such as blueprints and apps.

21 | 22 |
23 |
Clusters ($cluster_total)
24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | $clusters 35 | 36 |
TypeNameIP addressSoftwareCE?
37 |
38 |
39 | 40 |
41 |
Hosts ($host_total)
42 |
43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | $hosts 53 | 54 |
NameS/NIPCVM IP# of VMs
55 |
56 |
57 | 58 |
59 |
VMs ($vm_total)
60 |
61 | 62 | 63 | 64 | 65 | 66 | 67 | $vms 68 | 69 |
Cluster:NameDescription
70 |
71 |
72 | 73 |
74 |
Subnets ($subnet_total)
75 |
76 | 77 | 78 | 79 | 80 | 81 | 82 | $subnets 83 | 84 |
NameCluster
85 |
86 |
87 | 88 |
89 |
Projects ($project_total)
90 |
91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | $projects 101 | 102 |
NameVMsvCPUsStorage (GB)RAM (GB)
103 |
104 |
105 | 106 |
107 |
Apps ($app_total)
108 |
109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | $apps 117 | 118 |
NameProjectStatus
119 |
120 |
121 | 122 |
123 |
Blueprints ($blueprint_total)
124 |
125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | $blueprints 133 | 134 |
NameProjectStatus
135 |
136 |
137 | 138 | 153 | 154 |
155 |
Images ($image_total)
156 |
157 | 158 | 159 | 160 | 161 | 162 | 163 | $images 164 | 165 |
NameImage Type
166 |
167 |
168 | 169 |
170 | 171 | 174 | 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /python/get_energy_stats/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | venv/ 4 | .vscode/ 5 | 6 | .metrics 7 | *.pdf 8 | *.html 9 | 10 | *.pyc 11 | __pycache__/ 12 | 13 | .pytest_cache/ 14 | .coverage 15 | htmlcov/ 16 | 17 | dist/ 18 | build/ 19 | *.egg-info/ 20 | 21 | *.log 22 | *.swp 23 | -------------------------------------------------------------------------------- /python/get_energy_stats/README.md: -------------------------------------------------------------------------------- 1 | # Get Energy Stats 2 | 3 | ## Create and activate Python virtual environment 4 | 5 | This section explains how to create a Python virtual environment and install the required non-standard libraries using `pip`. 6 | 7 | Setting Up the Python Virtual Environment 8 | To ensure that your project dependencies are isolated from other projects and the system Python packages, it is recommended to use a virtual environment. Follow these steps to set up a virtual environment and install the required libraries: 9 | 10 | 1. Create a Virtual Environment 11 | 12 | - Open a terminal and navigate to your project directory: 13 | 14 | Create a virtual environment named venv: 15 | 16 | ``` 17 | python3 -m venv .virtualenvpower 18 | ``` 19 | 20 | 2. Activate the Virtual Environment 21 | 22 | On macOS and Linux: 23 | 24 | ``` 25 | source .virtualenvpower/bin/activate 26 | ``` 27 | 28 | On Windows: 29 | 30 | ``` 31 | .virtualenvpower\Scripts\activate 32 | ``` 33 | 34 | ## Install Script Dependencies 35 | 36 | 3. Install Required Libraries 37 | 38 | With the virtual environment activated, install the required non-standard libraries using pip. The libraries needed for this project are listed below: 39 | 40 | - requests 41 | - prettytable 42 | 43 | You can install these libraries by running the following command: 44 | 45 | ``` 46 | pip install -r requirements.txt 47 | ``` 48 | 49 | Alternatively, the latest versions of each library can be installed by running the following command: 50 | 51 | ``` 52 | pip install requests prettytable 53 | ``` 54 | 55 | 4. Verify Installation 56 | 57 | To verify that the libraries have been installed correctly, you can list the installed packages: 58 | 59 | ``` 60 | pip list 61 | ``` 62 | 63 | You should see `requests` and `prettytable` listed among the installed packages. 64 | 65 | 5. Deactivate the Virtual Environment 66 | 67 | Once you are done working in the virtual environment, you can deactivate it by running: 68 | 69 | ``` 70 | deactivate 71 | ``` 72 | 73 | By following these steps, you will have a virtual environment set up with the necessary libraries installed, ensuring that your project dependencies are managed effectively. 74 | -------------------------------------------------------------------------------- /python/get_energy_stats/requirements.txt: -------------------------------------------------------------------------------- 1 | requests==2.32.3 2 | prettytable==3.15.1 3 | -------------------------------------------------------------------------------- /python/get_host_details/.gitignore: -------------------------------------------------------------------------------- 1 | venv/ 2 | -------------------------------------------------------------------------------- /python/get_host_details/get_host_details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/get_host_details/get_host_details.png -------------------------------------------------------------------------------- /python/get_host_details/get_host_details.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Script to fetch details regarding CPUs, Memory configuration, 5 | Bios and BMC versions on a host. 6 | This script generates an excel sheet in the current directory of name 7 | host_script_timestamp 8 | """ 9 | from requests.auth import HTTPBasicAuth 10 | from datetime import datetime 11 | from pprint import pprint 12 | import requests 13 | import sys 14 | import json 15 | import time 16 | import xlsxwriter 17 | import urllib3 18 | 19 | ''' 20 | disable insecure connection warnings 21 | please be advised and aware of the implications of doing this 22 | in a production environment! 23 | ''' 24 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 25 | 26 | peVIP = "" # Prism Element VIP 27 | baseUrl = "https://" + peVIP + ":9440/PrismGateway/services/rest/v2.0/" # Base Url v2 API 28 | headers = {'ContentType':'application/json'} 29 | user = "admin" 30 | passw = "" 31 | hostObj = "hosts" # endpoint for hosts 32 | 33 | # standard get Request 34 | def getRequest(baseUrl, user, passw, obj): 35 | comUrl = baseUrl + obj + "/" 36 | r = requests.get(comUrl, auth=(user, passw), verify=False) 37 | return r.json() 38 | 39 | # standard post Request 40 | def postRequest(baseUrl, user, passw, obj, data): 41 | comUrl = baseUrl + obj + "/" 42 | print("URL: ", comUrl) 43 | dumpData = json.dumps(cloneData, separators=(',', ':')) 44 | print("type", type(dumpData)) 45 | print(dumpData) 46 | r = requests.post(comUrl, auth=(user, passw), data=dumpData, verify=False) 47 | return r.status_code 48 | 49 | 50 | # standard delete request 51 | def deleteRequest(baseUrl, user, passw, obj, uuid): 52 | comUrl = baseUrl + obj + "/" + uuid 53 | print("URL: ", comUrl) 54 | r = requests.delete(comUrl, auth=(user, passw), verify=False) 55 | return r.status_code 56 | 57 | 58 | # get a list of host Names and UUIDs 59 | # Return dictionary with name to host Mapping 60 | def getHostNames(hostObj): 61 | hostData = getRequest(baseUrl, user, passw, hostObj) 62 | nameUuidDict = {} 63 | for field in hostData["entities"]: 64 | nameUuidDict[field["name"]] = field["uuid"] 65 | return nameUuidDict 66 | 67 | # get individual statistics from each host 68 | # hostJson return json data structure for individual host 69 | # required parameters can be extracted from the host Json structure 70 | # returns a dictionary with hostname as the key and metrics as a list of values 71 | def getHostStats(nameUuidDict, hostObj): 72 | hostStatsDict = {} 73 | for name, uuid in nameUuidDict.items(): 74 | hostKeyObj = hostObj + "/" + uuid 75 | hostJson = getRequest(baseUrl, user, passw, hostKeyObj) 76 | hostStatsDict[name]= [ hostJson["serial"], hostJson["num_cpu_threads"], 77 | hostJson["num_vms"], hostJson["bios_version"], 78 | hostJson["bmc_version"], hostJson["memory_capacity_in_bytes"], 79 | hostJson["hypervisor_full_name"],hostJson["metadata_store_status"]] 80 | return hostStatsDict 81 | 82 | 83 | # create an excel sheet of host details in current directory 84 | def printHostStats(hostStatsDict): 85 | # Create a filename based on current timestamp and initialise worksheet 86 | now = datetime.now() 87 | dt_string = now.strftime("%d-%m-%y_%H-%M-%S") 88 | fileName = "host_report_" + dt_string + ".xlsx" 89 | print(fileName) 90 | workbook = xlsxwriter.Workbook(fileName) 91 | worksheet = workbook.add_worksheet() 92 | bold = workbook.add_format({'bold': True}) 93 | 94 | # Add data headers or titles for the metrics 95 | worksheet.write('A1', 'Hostname', bold) 96 | worksheet.write('B1', 'Node Serial', bold) 97 | worksheet.write('C1', 'CPUs per core', bold) 98 | worksheet.write('D1', 'No of VMs', bold) 99 | worksheet.write('E1', 'BIOS Version', bold) 100 | worksheet.write('F1', 'BMC Version', bold) 101 | worksheet.write('G1', 'Memory Capacity (bytes)', bold) 102 | worksheet.write('H1', 'Hypervisor OS', bold) 103 | worksheet.write('I1', 'Metadata Store', bold) 104 | 105 | # Set starting row and column on worksheet 106 | row = 1 107 | col = 0 108 | 109 | # Write data from Host dictionary to the excel sheet 110 | for name, values in hostStatsDict.items(): 111 | worksheet.write(row, col, name) 112 | for i, val in enumerate(values): 113 | worksheet.write(row, col + 1 + i, val) 114 | row += 1 115 | 116 | workbook.close() 117 | 118 | if __name__ == '__main__': 119 | nameUuidDict = getHostNames(hostObj) 120 | hostStatsDict = getHostStats(nameUuidDict, hostObj) 121 | printHostStats(hostStatsDict) -------------------------------------------------------------------------------- /python/get_host_details/get_host_details_spreadsheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/get_host_details/get_host_details_spreadsheet.png -------------------------------------------------------------------------------- /python/get_host_details/readme.rst: -------------------------------------------------------------------------------- 1 | Python Code Samples - get_host_details.py 2 | ######################################### 3 | 4 | This readme file is specifically for the **get_host_details.py** Python code sample. 5 | 6 | The setup instructions are the same as all other python code samples in this repository. This file is provided as additional/supplemental information for this specific code sample. 7 | 8 | Please see the `main `_ page for general instructions. 9 | 10 | Usage & Example 11 | --------------- 12 | 13 | It is strongly recommended that Python development and demo scripts are run using a `Python virtual environment `_. 14 | 15 | Example: 16 | 17 | #. Edit the script and replace all environment-specific variables so they match your environment. 18 | 19 | #. Create and activate the virtual environment: 20 | 21 | .. code-block:: bash 22 | 23 | python3.7 -m venv venv 24 | . venv/bin/activate 25 | 26 | #. Install dependencies: 27 | 28 | .. code-block:: bash 29 | 30 | pip3 install -e . 31 | 32 | #. Run the script: 33 | 34 | .. code-block:: bash 35 | 36 | python3.7 ./get_host_details.py 37 | 38 | Demo screenshot: 39 | 40 | .. figure:: ./get_host_details.png 41 | 42 | In the example above, **host_report_10-02-20_12-38-07.xlsx** has been generated and looks like the screenshot below: 43 | 44 | .. figure:: ./get_host_details_spreadsheet.png 45 | -------------------------------------------------------------------------------- /python/get_host_details/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | with open('readme.rst', encoding='UTF-8') as f: 4 | readme = f.read() 5 | 6 | setup( 7 | name='get_host_details', 8 | version='1.0', 9 | description='Use Python and the Nutanix Prism Element v2.0 APIs to collect configuration details of a cluster\'s physical hosts.', 10 | long_description=readme, 11 | author='Aditya Gawade', 12 | author_email='aditya.gawade@nutanix.com', 13 | install_requires=[ 14 | 'requests', 15 | 'urllib3', 16 | 'XlsxWriter' 17 | ], 18 | packages=find_packages('.'), 19 | package_dir={'': '.'} 20 | ) 21 | -------------------------------------------------------------------------------- /python/launch_calm_blueprint/environment_options/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ''' 4 | EnvironmentOptions class to work with the launch_calm_blueprint.py code sample 5 | ''' 6 | 7 | import argparse 8 | import getpass 9 | 10 | 11 | class EnvironmentOptions(): 12 | ''' 13 | this class is provided as an easy way to package the settings 14 | the script will use 15 | this isn't strictly necessary but does clean things up and removes 16 | the need for a bunch of individual global variables 17 | ''' 18 | 19 | def __init__(self): 20 | self.cluster_ip = "" 21 | self.username = "" 22 | self.password = "" 23 | self.debug = False 24 | self.read_timeout = 10 25 | # this the UUID for the blueprint we'll launch 26 | self.blueprint_uuid = '' 27 | self.app_profile_reference = '' 28 | 29 | def __repr__(self): 30 | ''' 31 | decent __repr__ for debuggability 32 | this is something recommended by Raymond Hettinger 33 | ''' 34 | return (f'{self.__class__.__name__}(cluster_ip={self.cluster_ip},' 35 | f'username={self.username},password=,' 36 | f'blueprint_uuid={self.blueprint_uuid},' 37 | f'app_name={self.app_name},app_desc={self.app_desc},' 38 | f'app_profile_reference={self.app_profile_reference},' 39 | f'read_timeout={self.read_timeout},debug={self.debug})') 40 | 41 | def get_options(self): 42 | ''' 43 | method to make sure our environment options class holds the 44 | settings provided by the user 45 | ''' 46 | 47 | parser = argparse.ArgumentParser() 48 | ''' 49 | pc_ip is the only mandatory command-line parameter for this script 50 | username and password have been left as optional so that we have 51 | the opportunity to prompt for them later - this is better for 52 | security and avoids the need to hard-code anything 53 | ''' 54 | parser.add_argument( 55 | 'pc_ip', 56 | help='Prism Central IP address' 57 | ) 58 | parser.add_argument( 59 | 'blueprint_uuid', 60 | help='UUID of the blueprint to be launched' 61 | ) 62 | parser.add_argument( 63 | 'app_name', 64 | help='The name of the application to be launched' 65 | ) 66 | parser.add_argument( 67 | 'app_desc', 68 | help='Description for the new application' 69 | ) 70 | parser.add_argument( 71 | '-a', 72 | '--app_profile', 73 | help='App profile reference UUID' 74 | ) 75 | parser.add_argument( 76 | '-u', 77 | '--username', 78 | help='Prism Central username' 79 | ) 80 | parser.add_argument( 81 | '-p', 82 | '--password', 83 | help='Prism Central password' 84 | ) 85 | parser.add_argument( 86 | '-d', 87 | '--debug', 88 | help='Enable/disable debug mode' 89 | ) 90 | 91 | args = parser.parse_args() 92 | 93 | ''' 94 | do some checking to see which parameters we still need to prompt for 95 | conditional statements make sense here because a) we're doing a few of 96 | them and b) they're more 'Pythonic' 97 | ''' 98 | self.username = (args.username if args.username else 99 | input('Please enter your Prism Central username: ')) 100 | self.password = args.password if args.password else getpass.getpass() 101 | 102 | ''' 103 | conditional statement isn't required for the Prism Central IP since 104 | it is a required parameter managed by argparse 105 | ''' 106 | self.cluster_ip = args.pc_ip 107 | self.blueprint_uuid = args.blueprint_uuid 108 | self.app_name = args.app_name 109 | self.app_desc = args.app_desc 110 | self.app_profile_reference = (args.app_profile if args.app_profile 111 | else '') 112 | 113 | self.debug = True if args.debug == 'enable' else False 114 | -------------------------------------------------------------------------------- /python/launch_calm_blueprint/exceptions/__init__.py: -------------------------------------------------------------------------------- 1 | class DetailsMissingException(Exception): 2 | ''' 3 | basic custom exception for when things "don't work" 4 | this is something that has been added simply to make extending 5 | the script much easier later 6 | ''' 7 | pass 8 | -------------------------------------------------------------------------------- /python/launch_calm_blueprint/readme.rst: -------------------------------------------------------------------------------- 1 | ##################### 2 | Launch Calm Blueprint 3 | ##################### 4 | 5 | Python script to launch a Nutanix Calm blueprint via the v3 REST API. 6 | 7 | High-level testing has been carried out on AOS version 5.10.5. Other versions may cause unpredictable results. 8 | 9 | ********** 10 | Disclaimer 11 | ********** 12 | 13 | This is **not** a production-grade script. Please make sure you add appropriate exception handling and error-checking before running it in production. See note re versions below, too. 14 | 15 | ****** 16 | Author 17 | ****** 18 | 19 | Chris Rasmussen, Developer Content Architect, Nutanix (Melbourne, AU) 20 | 21 | ********* 22 | Changelog 23 | ********* 24 | 25 | - 2019.07.23 - Code sample created 26 | 27 | ******* 28 | Details 29 | ******* 30 | 31 | Connect to a Nutanix Prism Central instance, provide a Nutanix Calm blueprint UUID then launch the blueprint. 32 | 33 | The intention is to use this approach for the launch of Nutanix Calm blueprints as part of external script workflows. 34 | 35 | Requires only the blueprint UUID; all other requirements are extracted from the blueprint by making other API requests. 36 | 37 | Modules 38 | ======= 39 | 40 | Two major parts of the script have been broken out into separate modules: 41 | 42 | - EnvironmentOptions 43 | - ApiClient 44 | 45 | As each name suggests, command-line/environment options are handled by **EnvironmentOptions** and the API requests are handled by **ApiClient**. 46 | 47 | This isn't mandatory but can form the basis for good practice later. 48 | 49 | ***** 50 | Usage 51 | ***** 52 | 53 | Virtual Environment 54 | =================== 55 | 56 | All the steps below assume you have a terminal session running with the current directory set to the location of the script. 57 | 58 | - It is strongly recommended to run development scripts like this within a virtual environment. For example, if using Python 3.7 on Linux: 59 | 60 | .. code-block:: bash 61 | 62 | python3.7 -m venv venv 63 | . venv/bin/activate 64 | 65 | - Install dependencies: 66 | 67 | .. code-block:: bash 68 | 69 | pip3 install -e . 70 | 71 | - Edit basic parameters 72 | 73 | - **self.read_timeout** - Increase or decrease depending on the desired timeout delay (in seconds) for each request 74 | 75 | Script Command Line 76 | =================== 77 | 78 | .. code-block:: bash 79 | 80 | ./launch_calm_blueprint_v3.py --help 81 | 82 | Generates: 83 | 84 | .. code-block:: bash 85 | 86 | usage: launch_calm_blueprint_v3.py [-h] [-a APP_PROFILE] [-u USERNAME] 87 | [-p PASSWORD] [-d DEBUG] 88 | pc_ip blueprint_uuid app_name app_desc 89 | 90 | positional arguments: 91 | pc_ip Prism Central IP address 92 | blueprint_uuid UUID of the blueprint to be launched 93 | app_name The name of the application to be launched 94 | app_desc Description for the new application 95 | 96 | optional arguments: 97 | -h, --help show this help message and exit 98 | -a APP_PROFILE, --app_profile APP_PROFILE 99 | App profile reference UUID 100 | -u USERNAME, --username USERNAME 101 | Prism Central username 102 | -p PASSWORD, --password PASSWORD 103 | Prism Central password 104 | -d DEBUG, --debug DEBUG 105 | Enable/disable debug mode 106 | 107 | APP_PROFILE parameter 108 | ===================== 109 | 110 | If the **APP_PROFILE** parameter is not specified using **-a** or **--app_profile**, the script will look for an application profile named **Default**. If no application is found with the name **Default**, the API will throw an HTTP 422 error that indicates the provided app_profile_reference does not match the required format. The script could easily be modified to check for this case, but has been written this way so users can see what happens in this instance. For example: 111 | 112 | .. code-block:: bash 113 | 114 | An HTTP client error has occurred (422) 115 | Details: {'spec.app_profile_reference.uuid': ["u'' does not match '^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$'"]} 116 | Message: Request could not be processed. 117 | Reason: INVALID_REQUEST 118 | 119 | ***** 120 | Notes 121 | ***** 122 | 123 | - High-level testing has been carried out on AOS version 5.10.5. 124 | - Other versions may produce unpredictable results. 125 | - The installation of specific Python versions, pip3 etc are beyond the scope of this readme 126 | 127 | ******* 128 | Example 129 | ******* 130 | 131 | A complete command-line example including all required parameters and optional **--app_profile** is shown below: 132 | 133 | .. code-block:: bash 134 | 135 | ./launch_calm_blueprint_v3.py 10.134.72.95 22f83818-de02-4d91-8fff-123d067e2fff SimpleLaunchDemo14 "Simple Launch Demo 14" --debug enable -u -p -a cea75177-61f8-4e14-b8ef-339a36b055f1; 136 | 137 | ********** 138 | Screenshot 139 | ********** 140 | 141 | This is what the script looks like as it is run (debug mode enabled). This screenshot is the output of the example command above. 142 | 143 | .. figure:: screenshot.png 144 | 145 | The same command with debug **disabled** shows output as per the screenshot below: 146 | 147 | .. figure:: screenshot_no_debug.png 148 | 149 | ******* 150 | Support 151 | ******* 152 | 153 | These scripts are *unofficial* and are not supported or maintained by Nutanix in any way. 154 | 155 | In addition, please also be advised that these scripts may run and operate in ways that do not follow best practices. Please check through each script to ensure it meets your requirements. 156 | 157 | **Changes will be required before these scripts can be used in production environments.** -------------------------------------------------------------------------------- /python/launch_calm_blueprint/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/launch_calm_blueprint/screenshot.png -------------------------------------------------------------------------------- /python/launch_calm_blueprint/screenshot_no_debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/launch_calm_blueprint/screenshot_no_debug.png -------------------------------------------------------------------------------- /python/launch_calm_blueprint/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | with open('readme.rst', encoding='UTF-8') as f: 4 | readme = f.read() 5 | 6 | setup( 7 | name='launch_calm_blueprint_v3', 8 | version='1.0', 9 | description='Use Prism Central v3 API to launch a Nutanix Calm blueprint.', 10 | long_description=readme, 11 | author='Chris Rasmussen', 12 | author_email='crasmussen@nutanix.com', 13 | install_requires=[ 14 | 'requests', 15 | 'urllib3' 16 | ], 17 | packages=find_packages('.'), 18 | package_dir={'': '.'} 19 | ) 20 | -------------------------------------------------------------------------------- /python/list_vm_v3_large/.gitignore: -------------------------------------------------------------------------------- 1 | venv/ 2 | list_vm_v3_large.json 3 | -------------------------------------------------------------------------------- /python/list_vm_v3_large/list_vm_v3_large.json: -------------------------------------------------------------------------------- 1 | {"cluster_ip":"10.0.0.0","username":"admin"} 2 | -------------------------------------------------------------------------------- /python/list_vm_v3_large/list_vm_v3_large.json.sample: -------------------------------------------------------------------------------- 1 | {"cluster_ip":"10.0.0.1","username":"admin"} -------------------------------------------------------------------------------- /python/list_vm_v3_large/readme.rst: -------------------------------------------------------------------------------- 1 | Python Code Samples - list_vm_v3_large.py 2 | ######################################### 3 | 4 | This readme file is specifically for the **list_vm_v3_large.py** Python code sample. 5 | 6 | The setup instructions are the same as all other python code samples in this repository. This file is provided as additional/supplemental information for this specific code sample. 7 | 8 | Please see the main_ page for general instructions. 9 | 10 | **Usage instructions are shown at the bottom of this page.** 11 | 12 | Code Sample Details 13 | ................... 14 | 15 | A quick intro, first. The **list_vm_v3.py** code sample shows a basic demo of REST API interactions with Python 3. There is no provision for environments of a specific size as all API requests will be made with the default parameters. For example: 16 | 17 | - A maximum of 20 entities are returned with each request 18 | - No offset has been specified i.e. every request will return VMs starting 0-19 19 | 20 | In large environments this information is not overly useful. 21 | 22 | **list_vm_v3_large.py** has been provided with a number of additional capabilities and "architecture" choices: 23 | 24 | - Clusters with >500 VMs will be identified. 25 | - A single request will be made if the cluster has <=500 VMs i.e. VM 0-499. 26 | - Additional requests will be made for VMs 500-n (where n is the total number of VMs in the cluster). 27 | - The API request "work" has been broken out into a dedicated **RESTClient** class that exposes a public **send_request** method. 28 | - The **RESTClient** class constructor accepts an array of parameters so that a single instance of the **RESTClient** class can be reused. 29 | - The **send_request** method returns an instance of **RequestResponse**. 30 | - **RequestResponse** contains public properties for a response **code**, **message**, **details** and **json**, making it easy to see what the request result was in the event of a caught exception. 31 | - The **send_request** method will be called as many times as necessary so that all VMs are captured. For example: 32 | 33 | - A cluster with 1407 VMs will have the **send_request** method called three times. 34 | - The first request will returns VMs 0-499 (500 VMs). 35 | - The second request will return VMs 500-999 (500 VMs). 36 | - The third and final request will return VMs 1000-406 (407 VMs). 37 | 38 | - A final prompt ensures the script doesn't "flash" before the user can view the output. 39 | 40 | While this demo is considerably more "advanced" than the standard **list_vm_v3.py** demo, please still make sure to modify the code appropriately before you use it in production. 41 | 42 | An example of the script's output is shown below: 43 | 44 | .. figure:: script_output.png 45 | 46 | Usage 47 | ----- 48 | 49 | .. code-block:: bash 50 | 51 | usage: list_vm_v3_large.py [-h] json 52 | 53 | positional arguments: 54 | json JSON file containing query parameters 55 | 56 | optional arguments: 57 | -h, --help show this help message and exit 58 | 59 | Example: 60 | 61 | .. code-block:: bash 62 | 63 | /usr/bin/python3.7 ./list_vm_v3_large.py list_vm_v3_large.json 64 | 65 | .. _main: https://github.com/nutanixdev/code-samples/tree/master/python 66 | -------------------------------------------------------------------------------- /python/list_vm_v3_large/script_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/list_vm_v3_large/script_output.png -------------------------------------------------------------------------------- /python/nutanix_objects/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | venv/ 4 | .vscode/ 5 | 6 | .metrics 7 | *.pdf 8 | *.html 9 | 10 | *.pyc 11 | __pycache__/ 12 | 13 | .pytest_cache/ 14 | .coverage 15 | htmlcov/ 16 | 17 | dist/ 18 | build/ 19 | *.egg-info/ 20 | 21 | -------------------------------------------------------------------------------- /python/nutanix_objects/README.md: -------------------------------------------------------------------------------- 1 | # Nutanix Objects Operations 2 | 3 | Language: Python 3 4 | 5 | ## Description 6 | 7 | Various code samples to work with Nutanix Objects via API. 8 | 9 | - Upload a file to a Nutanix Objects bucket via the Object APIs 10 | - Create multiple Nutanix Objects buckets and attach lifecycle policy 11 | 12 | ## Suggested Usage for File Upload Demo 13 | 14 | Other scripts will follow almost identical steps. 15 | 16 | - Clone this repo 17 | - Edit `upload_file.py` and set appropriate variables to match your environment: 18 | 19 | - `endpoint_url`: An accessible "Objects Public IP" 20 | - `access_key`: The access key for your Objects credentials 21 | - `secret_key`: The secret key for your Objects credentials 22 | - `bucket`: The bucket to which the script will upload files 23 | - `filename`: The full path to the file that will be uploaded 24 | - `key`: Object key for which the PUT action was initiated 25 | 26 | - Create and activate a Python virtual environment: 27 | 28 | ``` 29 | python3.9 -m venv venv 30 | . venv/bin/activate 31 | ``` 32 | 33 | - Install dependencies: 34 | 35 | ``` 36 | pip3 install -r requirements.txt 37 | ``` 38 | 39 | Note: The `black` requirement is not mandatory for script usage. It has been included as an extra module to aid in correct code formatting. 40 | 41 | - Verify the filename specified by the `filename` variable exists and is accessible 42 | - Run the demo script, assuming your terminal's current directory is the directory containing `objects_upload.py`: 43 | 44 | ``` 45 | python ./upload_file.py 46 | ``` 47 | 48 | ### Example Output 49 | 50 | ![Upload files screenshot](./screenshot_upload_files.png) 51 | 52 | ## License 53 | 54 | Please see the `LICENSE` file distributed with this repository. 55 | 56 | ## Disclaimer 57 | 58 | Please see the `.disclaimer` file distributed with this repository. 59 | -------------------------------------------------------------------------------- /python/nutanix_objects/multiple_buckets.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | from botocore.exceptions import ClientError 3 | from botocore.exceptions import ParamValidationError 4 | import sys 5 | 6 | session = boto3.session.Session() 7 | 8 | # configuration for this connection 9 | # in a "real" script, these values would probably not be hard-coded 10 | configuration = { 11 | "endpoint_url": "[endpoint_url_here]", 12 | "access_key": "[access_key_here]", 13 | "secret_key": "[secret_key_here]", 14 | "buckets": { 15 | "web-assets", 16 | "form-submissions" 17 | } 18 | } 19 | 20 | # create our s3c session using the variables above 21 | # note "use_ssl=False", as outlined in the accompanying article 22 | s3c = session.client( 23 | aws_access_key_id=configuration["access_key"], 24 | aws_secret_access_key=configuration["secret_key"], 25 | endpoint_url=configuration["endpoint_url"], 26 | service_name="s3", 27 | use_ssl=False, 28 | ) 29 | 30 | # setup our bucket lifecycle policy 31 | # please use this carefully as these settings will need to be 32 | # altered before use outside this demo environment 33 | lifecycle_policy = { 34 | "Rules": [ 35 | { 36 | "Expiration": {"Days": 10}, 37 | "Filter": {"Prefix": "demo"}, 38 | "Status": "Enabled", 39 | "ID": "ExpiryPolicy-10Days-ObjectPrefix-demo", 40 | }, 41 | { 42 | "Expiration": {"Days": 30}, 43 | "Filter": {"Prefix": "object"}, 44 | "Status": "Enabled", 45 | "ID": "ExpiryPolicy-1Month-ObjectPrefix-object", 46 | } 47 | ] 48 | } 49 | 50 | # iterate over the bucket list, verify that each one does 51 | # not already exist and, if not, attempt to create it 52 | for bucket in configuration["buckets"]: 53 | pass 54 | 55 | # check if bucket exists 56 | try: 57 | s3c.head_bucket(Bucket=bucket) 58 | print(f"Bucket exists : {bucket}") 59 | except ClientError: 60 | print(f"Bucket {bucket} does not exist. " 61 | + "Attempting to create bucket ...") 62 | try: 63 | s3c.create_bucket(Bucket=bucket) 64 | except Exception as err: 65 | print("An exception occurred while creating the " 66 | + f"{bucket} bucket. " 67 | + f"Details: {err}") 68 | sys.exit() 69 | 70 | # bucket either already exists or we were able to create it 71 | # now apply the lifecycle policy 72 | try: 73 | print(f"Applying lifecycle policy to {bucket} bucket ...") 74 | s3c.put_bucket_lifecycle_configuration(Bucket=bucket, 75 | LifecycleConfiguration=lifecycle_policy) 76 | except s3c.exceptions.NoSuchBucket: 77 | print("Bucket does not exist.") 78 | except ParamValidationError as err: 79 | print("The provided lifecycle policy is invalid. Please check " 80 | + "your policy configuration. Details:") 81 | print(f"{err}") 82 | except Exception as err: 83 | print(err) 84 | -------------------------------------------------------------------------------- /python/nutanix_objects/requirements.txt: -------------------------------------------------------------------------------- 1 | boto3==1.17.84 2 | black==24.3.0 -------------------------------------------------------------------------------- /python/nutanix_objects/screenshot_upload_files.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/nutanix_objects/screenshot_upload_files.png -------------------------------------------------------------------------------- /python/nutanix_objects/upload_file.py: -------------------------------------------------------------------------------- 1 | import boto3 2 | from botocore.exceptions import ClientError 3 | import sys 4 | 5 | session = boto3.session.Session() 6 | 7 | # configuration for this connection 8 | # in a "real" script, these values would probably not be hard-coded 9 | configuration = { 10 | "endpoint_url": "[endpoint_url_here]", 11 | "access_key": "[access_key_here]", 12 | "secret_key": "[secret_key_here]", 13 | "bucket": "ntnxdev-uploads", 14 | "filename": "/tmp/hello_world.txt", 15 | "key": "hello_world.txt" 16 | } 17 | 18 | # create our s3c session using the variables above 19 | # note "use_ssl=False", as outlined in the accompanying article 20 | s3c = session.client( 21 | aws_access_key_id=configuration["access_key"], 22 | aws_secret_access_key=configuration["secret_key"], 23 | endpoint_url=configuration["endpoint_url"], 24 | service_name="s3", 25 | use_ssl=False, 26 | ) 27 | 28 | # check if bucket exists 29 | try: 30 | s3c.head_bucket(Bucket=configuration["bucket"]) 31 | print(f"Bucket exists : {configuration['bucket']}") 32 | except ClientError: 33 | print(f"Bucket {configuration['bucket']} does not exist. " 34 | + "Attempting to create bucket ...") 35 | try: 36 | s3c.create_bucket(Bucket=configuration['bucket']) 37 | except Exception as err: 38 | print("An exception occurred while creating the " 39 | + f"{configuration['bucket']} bucket. " 40 | + f"Details: {err}") 41 | sys.exit() 42 | 43 | try: 44 | # create file handle and upload the file to Objects endpoint. 45 | print(f"Uploading file {configuration['filename']}, as object " 46 | + "{configuration['key']} in bucket {configuration['bucket']} ...") 47 | s3c.put_object(Bucket=configuration["bucket"], 48 | Key=configuration["key"], 49 | Body=configuration["filename"]) 50 | 51 | # verify if file is uploaded 52 | print(f"Checking if {configuration['key']} exists ...") 53 | response = s3c.head_object(Bucket=configuration["bucket"], 54 | Key=configuration["key"]) 55 | print(f"Head Object Response : {response}") 56 | except s3c.exceptions.NoSuchBucket: 57 | print(f"The {configuration['bucket']} bucket does not exist. " 58 | + "Aborting ...") 59 | except Exception as err: 60 | print("An unexpected exception occurred while attempting " 61 | + "file upload. Details:") 62 | print(f"{err}") 63 | -------------------------------------------------------------------------------- /python/sample-chatbot/.gitignore: -------------------------------------------------------------------------------- 1 | venv/ 2 | __pycache__/ 3 | startup.json 4 | *.log* 5 | rc_setup.zsh 6 | dist/ 7 | full_image_update_etag.py 8 | full_image_update_requests.py 9 | .ruff_cache/ 10 | build/ 11 | dist/ 12 | *.egg-info/ 13 | eslint.config.mjs 14 | -------------------------------------------------------------------------------- /python/sample-chatbot/.streamlit/config.toml: -------------------------------------------------------------------------------- 1 | [theme] 2 | base="dark" 3 | primaryColor="#7855FA" 4 | font="sans serif" 5 | 6 | [ui] 7 | hideTopBar = true 8 | -------------------------------------------------------------------------------- /python/sample-chatbot/NOTICES: -------------------------------------------------------------------------------- 1 | Dependencies and Licenses 2 | ------------------------- 3 | 4 | streamlit: Apache 2.0 License, https://github.com/streamlit/streamlit/blob/develop/LICENSE 5 | streamlit-extras: Apache 2.0 License, https://github.com/arnaudmiribel/streamlit-extras/blob/main/LICENSE 6 | openai: Apache 2.0 License, https://github.com/openai/openai-python/blob/main/LICENSE 7 | -------------------------------------------------------------------------------- /python/sample-chatbot/README.md: -------------------------------------------------------------------------------- 1 | # Chatbot demo 2 | 3 | This is a real time chatbot demo that works with Nutanix Enterprise AI. 4 | 5 | ## Usage 6 | 7 | ### Create Virtual Environment 8 | 9 | ``` 10 | python -m venv venv 11 | . venv/bin/activate 12 | ``` 13 | 14 | ### Install Python requirements 15 | 16 | ``` 17 | pip install -r requirements.txt 18 | ``` 19 | 20 | ### Run app 21 | 22 | ``` 23 | streamlit run chat.py 24 | ``` -------------------------------------------------------------------------------- /python/sample-chatbot/chat.py: -------------------------------------------------------------------------------- 1 | from openai import OpenAI, DefaultHttpxClient 2 | import streamlit as st 3 | import os 4 | import time 5 | 6 | LOGO_SVG = "nutanix.svg" 7 | 8 | if "iep_host_disabled" not in st.session_state: 9 | st.session_state["iep_host_disabled"] = False 10 | 11 | def iep_host_disable(): 12 | st.session_state["iep_host_disabled"] = True 13 | 14 | if "endpoint_disabled" not in st.session_state: 15 | st.session_state["endpoint_disabled"] = False 16 | 17 | def endpoint_disable(): 18 | st.session_state["endpoint_disabled"] = True 19 | 20 | if "apikey_disabled" not in st.session_state: 21 | st.session_state["apikey_disabled"] = False 22 | 23 | def apikey_disable(): 24 | st.session_state["apikey_disabled"] = True 25 | 26 | if 'chat_disabled' not in st.session_state: 27 | st.session_state.chat_disabled = False 28 | 29 | if 'set_values' not in st.session_state: 30 | st.session_state.set_values = False 31 | 32 | if 'reset_values' not in st.session_state: 33 | st.session_state.reset_values = False 34 | 35 | if 'chat_default' not in st.session_state: 36 | st.session_state.chat_default = "Ask me" 37 | 38 | # App title 39 | st.title("Demo Chatbot") 40 | 41 | def clear_chat_history(): 42 | """ 43 | Clears the chat history by resetting the session state messages. 44 | """ 45 | st.session_state.messages = [] 46 | 47 | 48 | with st.sidebar: 49 | if os.path.exists(LOGO_SVG): 50 | _, col2, _, _ = st.columns(4) 51 | with col2: 52 | st.image(LOGO_SVG, width=150) 53 | 54 | st.title("Nutanix Enterprise AI") 55 | st.markdown( 56 | "Nutanix Enterprise AI a simple way to securely deploy, scale, and run LLMs " 57 | " with NVIDIA NIM optimized inference microservices as well as open foundation " 58 | "models from Hugging Face. Read the [announcement]" 59 | "(https://www.nutanix.com/press-releases/2024/nutanix-extends-ai-platform-to-public-cloud)" 60 | ) 61 | iep_host_name = st.sidebar.text_input( 62 | "Enter the Inference Endpoint URL", disabled=st.session_state.iep_host_disabled, on_change=iep_host_disable 63 | ) 64 | 65 | st.subheader("Endpoint Configuration") 66 | endpoint_name = st.sidebar.text_input( 67 | "Enter the Endpoint name", disabled=st.session_state.endpoint_disabled, on_change=endpoint_disable 68 | ) 69 | endpoint_api_key = st.sidebar.text_input( 70 | "Enter the Endpoint API key", disabled=st.session_state.apikey_disabled, on_change=apikey_disable, type="password" 71 | ) 72 | 73 | if "iep_host_name" in st.session_state and st.session_state["iep_host_name"] != iep_host_name: 74 | clear_chat_history() 75 | 76 | if "endpoint_name" in st.session_state and st.session_state["endpoint_name"] != endpoint_name: 77 | clear_chat_history() 78 | 79 | if "endpoint_api_key" in st.session_state and st.session_state["endpoint_api_key"] != endpoint_api_key: 80 | clear_chat_history() 81 | 82 | st.session_state["iep_host_name"] = iep_host_name.strip() 83 | st.session_state["endpoint_name"] = endpoint_name.strip() 84 | st.session_state["endpoint_api_key"] = endpoint_api_key.strip() 85 | 86 | def set_values(): 87 | st.session_state.set_values = True 88 | st.session_state.iep_host_disabled = True 89 | st.session_state.endpoint_disabled = True 90 | st.session_state.apikey_disabled = True 91 | 92 | def reset_values(): 93 | st.session_state.reset_values = True 94 | st.session_state.iep_host_disabled = False 95 | st.session_state.endpoint_disabled = False 96 | st.session_state.apikey_disabled = False 97 | clear_chat_history() 98 | 99 | col1, _ ,col3 = st.columns(3) 100 | with col1: 101 | st.button('Save', on_click=set_values) 102 | with col3: 103 | st.button('Reset', on_click=reset_values, use_container_width=True) 104 | 105 | #if st.session_state.set_values: 106 | if not endpoint_name or not endpoint_api_key or not iep_host_name: 107 | st.session_state.chat_default="Endpoint URL, Name, and API key must be set" 108 | st.session_state.chat_disabled=True 109 | else: 110 | st.session_state.chat_default="Ask me" 111 | st.session_state.chat_disabled=False 112 | 113 | client = OpenAI(base_url=iep_host_name.removesuffix("/chat/completions"), api_key=endpoint_api_key, http_client=DefaultHttpxClient(verify=False)) 114 | 115 | if "messages" not in st.session_state: 116 | st.session_state.messages = [] 117 | 118 | for message in st.session_state.messages: 119 | with st.chat_message(message["role"]): 120 | st.markdown(message["content"]) 121 | 122 | if prompt := st.chat_input(st.session_state.chat_default, disabled=st.session_state.chat_disabled): 123 | st.session_state.messages.append({"role": "user", "content": prompt}) 124 | with st.chat_message("user"): 125 | st.markdown(prompt) 126 | 127 | try: 128 | with st.chat_message("assistant"): 129 | start = time.perf_counter() 130 | stream = client.chat.completions.create( 131 | model=st.session_state["endpoint_name"], 132 | messages=[ 133 | {"role": m["role"], "content": m["content"]} 134 | for m in st.session_state.messages 135 | ], 136 | max_tokens=1024, 137 | stream=True, 138 | ) 139 | response = st.write_stream(stream) 140 | request_time = "{:.2f}".format(time.perf_counter() - start) 141 | st.session_state.messages.append({"role": "assistant", "content": response}) 142 | st.markdown(f"Latency: {request_time} seconds") 143 | print(request_time) 144 | 145 | except Exception as e: 146 | print(e) 147 | st.error("Error. Did you set Inference Endpoint host name, Endpoint name and API key correctly?") 148 | -------------------------------------------------------------------------------- /python/sample-chatbot/nutanix.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 32 | 33 | -------------------------------------------------------------------------------- /python/sample-chatbot/requirements.txt: -------------------------------------------------------------------------------- 1 | openai==1.20.0 2 | streamlit==1.31 3 | streamlit-extras==0.3.5 -------------------------------------------------------------------------------- /python/script_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/script_output.png -------------------------------------------------------------------------------- /python/v4api_client/README.md: -------------------------------------------------------------------------------- 1 | # Nutanix v4 API Sample Scripts 2 | 3 | Code sample to demonstrate use of the new Nutanix v4 APIs via Python client. 4 | 5 | Requires Prism Central 2024.1 or later and AOS 6.8 or later. 6 | 7 | ## Recommendations 8 | 9 | These demos are specifically for environments where the use of Nutanix v4 SDKs is not possible. Where possible, it is recommended to use and implement the Nutanix v4 SDKs. 10 | 11 | ## Usage 12 | 13 | - Create and activate a Python virtual environment: 14 | 15 | ``` 16 | python -m venv venv 17 | . venv/bin/activate 18 | ``` 19 | 20 | - Install required packages: 21 | 22 | ``` 23 | pip install -r requirements.txt 24 | ``` 25 | 26 | - Run script: 27 | 28 | ``` 29 | python list_images_client.py 30 | ``` 31 | 32 | Note: User will be prompted for password 33 | 34 | -------------------------------------------------------------------------------- /python/v4api_client/list_images_client.py: -------------------------------------------------------------------------------- 1 | """ 2 | Use the Nutanix v4 REST APIs to request and parse a list of all available images 3 | """ 4 | 5 | import requests 6 | import urllib3 7 | import getpass 8 | import argparse 9 | from base64 import b64encode 10 | 11 | """ 12 | suppress warnings about insecure connections 13 | please consider the security implications before doing this in a production environment 14 | """ 15 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 16 | 17 | """ 18 | setup the command line parameters 19 | for this example only two parameters are required 20 | - the Prism Central IP address or FQDN 21 | - the Prism Central username; the script will prompt for the user's password 22 | so that it never needs to be stored in plain text 23 | """ 24 | parser = argparse.ArgumentParser() 25 | parser.add_argument("pc_ip", help="Prism Central IP address or FQDN") 26 | parser.add_argument("username", help="Prism Central username") 27 | args = parser.parse_args() 28 | 29 | # get the cluster password 30 | cluster_password = getpass.getpass( 31 | prompt="Please enter your Prism Central \ 32 | password: ", 33 | stream=None, 34 | ) 35 | 36 | pc_ip = args.pc_ip 37 | username = args.username 38 | 39 | # make sure the user enters a password 40 | if not cluster_password: 41 | while not cluster_password: 42 | print( 43 | "Password cannot be empty. Please enter a password or Ctrl-C/Ctrl-D to exit." 44 | ) 45 | cluster_password = getpass.getpass( 46 | prompt="Please enter your Prism Central password: ", stream=None 47 | ) 48 | 49 | try: 50 | 51 | """ 52 | setup the HTTP Basic Authorization header based on the 53 | supplied username and password 54 | """ 55 | encoded_credentials = b64encode( 56 | bytes(f"{username}:{cluster_password}", encoding="ascii") 57 | ).decode("ascii") 58 | auth_header = f"Basic {encoded_credentials}" 59 | # setup the URL that will be used for the API request 60 | url = f"https://{pc_ip}:9440/api/vmm/v4.0.b1/content/images" 61 | 62 | """ 63 | setup the request headers 64 | note the use of {auth_header} i.e. the Basic Authorization 65 | credentials we setup earlier 66 | """ 67 | headers = { 68 | "Accept": "application/json", 69 | "Content-Type": "application/json", 70 | "Authorization": f"{auth_header}", 71 | "cache-control": "no-cache", 72 | } 73 | # submit the request 74 | try: 75 | response = requests.request( 76 | "GET", url, headers=headers, verify=False, timeout=10 77 | ) 78 | if response.ok: 79 | # show a total count of images found 80 | print( 81 | f'Total images found: {response.json()["metadata"]["totalAvailableResults"]}:' 82 | ) 83 | for image in response.json()["data"]: 84 | print(f'- {image["name"]}') 85 | else: 86 | print(f"An error occurred while connecting to {pc_ip}.") 87 | """ 88 | the following line can be uncommented to show 89 | detailed error information 90 | """ 91 | print(response.text) 92 | except Exception as ex: 93 | print( 94 | f"An {type(ex).__name__} exception occurred while \ 95 | connecting to {pc_ip}.\nArgument: {ex.args}." 96 | ) 97 | 98 | # catching all exceptions like this should be generally be avoided 99 | except Exception as e: 100 | print(f"{e}") 101 | -------------------------------------------------------------------------------- /python/v4api_client/requirements.txt: -------------------------------------------------------------------------------- 1 | requests==2.31.0 2 | ruff==0.1.15 3 | -------------------------------------------------------------------------------- /python/v4api_client/update_image_etag_client.py: -------------------------------------------------------------------------------- 1 | """ 2 | Use the Nutanix v4 REST APIs to update a Prism Central image 3 | """ 4 | 5 | import requests 6 | import urllib3 7 | import getpass 8 | import argparse 9 | import uuid 10 | import json 11 | import sys 12 | from base64 import b64encode 13 | 14 | """ 15 | suppress warnings about insecure connections 16 | please consider the security implications before doing this in a production environment 17 | """ 18 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 19 | 20 | """ 21 | setup the command line parameters 22 | for this example only two parameters are required 23 | - the Prism Central IP address or FQDN 24 | - the Prism Central username; the script will prompt for the user's password 25 | so that it never needs to be stored in plain text 26 | """ 27 | parser = argparse.ArgumentParser() 28 | parser.add_argument("pc_ip", help="Prism Central IP address or FQDN") 29 | parser.add_argument("username", help="Prism Central username") 30 | args = parser.parse_args() 31 | 32 | # get the cluster password 33 | cluster_password = getpass.getpass( 34 | prompt="Please enter your Prism Central \ 35 | password: ", 36 | stream=None, 37 | ) 38 | 39 | pc_ip = args.pc_ip 40 | username = args.username 41 | 42 | # make sure the user enters a password 43 | if not cluster_password: 44 | while not cluster_password: 45 | print( 46 | "Password cannot be empty. Please enter a password or Ctrl-C/Ctrl-D to exit." 47 | ) 48 | cluster_password = getpass.getpass( 49 | prompt="Please enter your Prism Central password: ", stream=None 50 | ) 51 | 52 | try: 53 | 54 | """ 55 | setup the HTTP Basic Authorization header based on the 56 | supplied username and password 57 | """ 58 | encoded_credentials = b64encode( 59 | bytes(f"{username}:{cluster_password}", encoding="ascii") 60 | ).decode("ascii") 61 | auth_header = f"Basic {encoded_credentials}" 62 | # setup the URL that will be used for the API request 63 | url = f"https://{pc_ip}:9440/api/vmm/v4.0.b1/content/images" 64 | 65 | """ 66 | setup the request headers 67 | note the use of {auth_header} i.e. the Basic Authorization 68 | credentials we setup earlier 69 | """ 70 | headers = { 71 | "Accept": "application/json", 72 | "Content-Type": "application/json", 73 | "Authorization": f"{auth_header}", 74 | "cache-control": "no-cache", 75 | } 76 | # submit the request 77 | try: 78 | response = requests.request( 79 | "GET", url, headers=headers, verify=False, timeout=10 80 | ) 81 | if response.ok: 82 | # show a total count of images found 83 | print( 84 | f'Total images found: {response.json()["metadata"]["totalAvailableResults"]}' 85 | ) 86 | else: 87 | print(f"An error occurred while connecting to {pc_ip}.") 88 | """ 89 | the following line can be uncommented to show 90 | detailed error information 91 | """ 92 | print(response.text) 93 | sys.exit() 94 | 95 | # images have been found - update the first image in the list 96 | # to begin, we must retrieve that image's details 97 | existing_image_ext_id = response.json()["data"][0]["extId"] 98 | # get the existing image details 99 | url = f"https://{pc_ip}:9440/api/vmm/v4.0.a1/content/images/{existing_image_ext_id}" 100 | existing_image = requests.get(url, headers=headers, verify=False, timeout=10) 101 | 102 | # get the existing image's resource Etag 103 | existing_image_etag = existing_image.headers["Etag"] 104 | 105 | # create a new UUID to be used as the value of the Ntnx-Request-Id header 106 | request_id = str(uuid.uuid1()) 107 | 108 | # create new headers that include the existing image's resource Etag and Ntnx-Request-Id 109 | headers = { 110 | "Accept": "application/json", 111 | "Content-Type": "application/json", 112 | "Authorization": f"{auth_header}", 113 | "cache-control": "no-cache", 114 | "If-Match": existing_image_etag, 115 | "Ntnx-Request-Id": request_id, 116 | } 117 | 118 | # create the image update's JSON request payload 119 | update_payload = existing_image.json()["data"] 120 | 121 | # alter the image's name 122 | update_payload["name"] = f'{update_payload["name"]} - Updated' 123 | 124 | # update the image 125 | url = f"https://{pc_ip}:9440/api/vmm/v4.0.a1/content/images/{existing_image_ext_id}" 126 | update = requests.put(url, headers=headers, data=json.dumps(update_payload), verify=False, timeout=10) 127 | print(update.json()) 128 | 129 | except Exception as ex: 130 | print( 131 | f"An {type(ex).__name__} exception occurred while \ 132 | connecting to {pc_ip}.\nArgument: {ex.args}." 133 | ) 134 | 135 | # catching all exceptions like this should be generally be avoided 136 | except Exception as e: 137 | print(f"{e}") 138 | -------------------------------------------------------------------------------- /python/v4api_sdk/.gitignore: -------------------------------------------------------------------------------- 1 | venv/ 2 | __pycache__/ 3 | startup.json 4 | *.log* 5 | rc_setup.zsh 6 | dist/ 7 | full_image_update_etag.py 8 | full_image_update_requests.py 9 | .ruff_cache/ 10 | build/ 11 | dist/ 12 | *.egg-info/ 13 | eslint.config.mjs 14 | ntnx_opsmgmt_py_client/ 15 | test.py 16 | -------------------------------------------------------------------------------- /python/v4api_sdk/README.md: -------------------------------------------------------------------------------- 1 | # Nutanix v4 SDK Sample Scripts 2 | 3 | Code samples to demonstrate use of the new Nutanix v4 APIs via Python SDK. 4 | 5 | ## Requirements 6 | 7 | - Python 3.6, 3.7, 3.8 and 3.9 are officially supported 8 | - Nutanix Prism Central 2024.1 or later 9 | - Nutanix AOS 6.8 or later 10 | 11 | ## Usage 12 | 13 | - Create and activate a Python virtual environment: 14 | 15 | ``` 16 | python -m venv venv 17 | . venv/bin/activate 18 | ``` 19 | 20 | - Install required packages: 21 | 22 | ``` 23 | pip install -r requirements.txt 24 | ``` 25 | 26 | - Run script e.g. list Prism Central images: 27 | 28 | ``` 29 | python list_images_sdk.py 30 | ``` 31 | 32 | Note: User will be prompted for password 33 | 34 | ## Testing 35 | 36 | This repository provides two additional files. Using them is optional. 37 | 38 | - `startup.example.json`: Should be renamed to `startup.json` and edited to contain details appropriate for your environment. 39 | - `startup.py`: A script that can be used to initialise the Python REPL during testing. This script will import various Nutanix Python SDKS, instantiate the SDKs and create objects useful during testing. Note: This script is for testing only and contains very limited error checking and validation. 40 | 41 | To use these optional files, continue below: 42 | 43 | - Create and activate Python virtual environment as per the steps above 44 | - Rename `startup.json.example` to `startup.json` 45 | - Edit `startup.json` to contain values appropriate for your environment 46 | - Initialise the Python REPL using `startup.py`: 47 | 48 | ``` 49 | python -i startup.py 50 | ``` 51 | - If the script returns no errors, initialisation was successful. 52 | 53 | ## Screenshots 54 | 55 | ### List Images 56 | 57 | ![List Images](./screenshot_list_images.png) 58 | 59 | ### Create Image 60 | 61 | ![Create image](./screenshot_create_image.png) 62 | 63 | ### Batch Operations 64 | 65 | ![Batch Operations - Create](./screenshot_batch_create.png) 66 | ![Batch Operations - Modify](./screenshot_batch_modify.png) 67 | 68 | ### Create Network Security Policy 69 | 70 | ![Create Network Security Policy](./screenshot_create_nsp1.png) 71 | ![Create Network Security Policy](./screenshot_create_nsp2.png) 72 | 73 | ### Create Categories 74 | 75 | ![Create Categories](./screenshot_create_cats.png) 76 | 77 | ### Create Networking Subnet 78 | 79 | ![Create Networking Subnet](./screenshot_create_subnet.png) 80 | 81 | ### Create Virtual Machine 82 | 83 | ![Create Virtual Machine](./screenshot_create_vm.png) 84 | -------------------------------------------------------------------------------- /python/v4api_sdk/categories/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | venv/ 3 | -------------------------------------------------------------------------------- /python/v4api_sdk/categories/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Nutanix Inc. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /python/v4api_sdk/categories/NOTICES: -------------------------------------------------------------------------------- 1 | Dependencies and Licenses 2 | ------------------------- 3 | 4 | urllib3: MIT License, https://github.com/urllib3/urllib3/blob/main/LICENSE.txt 5 | ntnx-clustermgmt-py-client: Nutanix Proprietary License, https://developers.nutanix.com/license 6 | ntnx-prism-py-client: Nutanix Proprietary License, https://developers.nutanix.com/license 7 | ntnx-vmm-py-client: Nutanix Proprietary License, https://developers.nutanix.com/license 8 | -------------------------------------------------------------------------------- /python/v4api_sdk/categories/README.md: -------------------------------------------------------------------------------- 1 | # Categories v4 Workflow Sample Scripts 2 | 3 | Code sample to demonstrate use of the Categories v4 APIs via Python client. 4 | 5 | Requires Prism Central 2024.3 or later and AOS 6.8 or later. 6 | 7 | ## Usage 8 | 9 | - Create and activate a Python virtual environment: 10 | 11 | ``` 12 | python -m venv venv 13 | . venv/bin/activate 14 | ``` 15 | 16 | - Install required packages: 17 | 18 | ``` 19 | pip install -r requirements.txt 20 | ``` 21 | 22 | - Run script: 23 | 24 | ``` 25 | python categories_v4_workflow.py --pc_ip --username 26 | ``` 27 | 28 | **Note:** 29 | 30 | 1. **Password for the provided username**: 31 | You will be prompted to enter the password associated with the specified username. 32 | 33 | 2. **Cluster name**: 34 | Ensure you provide the correct Cluster name. This will be used to create the VM, and it must be accurate to avoid any configuration errors. 35 | 36 | 3. **New owner extId (UUID)**: 37 | Provide the `IAM user extId (UUID)` to update the `owner_uuid` of the category. The `extId` must be correct for the script to execute successfully. 38 | -------------------------------------------------------------------------------- /python/v4api_sdk/categories/requirements.txt: -------------------------------------------------------------------------------- 1 | urllib3==1.26.20 2 | ntnx-clustermgmt-py-client==4.0.1 3 | ntnx-prism-py-client==4.0.1 4 | ntnx-vmm-py-client==4.0.1 -------------------------------------------------------------------------------- /python/v4api_sdk/category_specs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "category_name1", 4 | "value": "category_value", 5 | "description": "category created with v4 Prism SDK" 6 | }, 7 | { 8 | "name": "category_name2", 9 | "value": "category_value", 10 | "description": "category created with v4 Prism SDK" 11 | }, 12 | { 13 | "name": "category_name2", 14 | "value": "category_value2", 15 | "description": "category created with v4 Prism SDK" 16 | } 17 | ] 18 | -------------------------------------------------------------------------------- /python/v4api_sdk/docs/index.md: -------------------------------------------------------------------------------- 1 | # Nutanix Code Samples 2 | 3 | Coming soon. 4 | -------------------------------------------------------------------------------- /python/v4api_sdk/dr/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | venv/ 3 | -------------------------------------------------------------------------------- /python/v4api_sdk/dr/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Nutanix Inc. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /python/v4api_sdk/dr/NOTICES: -------------------------------------------------------------------------------- 1 | Dependencies and Licenses 2 | ------------------------- 3 | 4 | ntnx-dataprotection-py-client: Nutanix Proprietary License, https://developers.nutanix.com/license 5 | -------------------------------------------------------------------------------- /python/v4api_sdk/dr/README.md: -------------------------------------------------------------------------------- 1 | # Nutanix v4 Disaster Recovery APIs 2 | 3 | The code samples in this directory are intended for use in conjunction with the following [Nutanix.dev](https://www.nutanix.dev) articles: 4 | 5 | - [Nutanix v4 Disaster Recovery API Series Part 1: Volume Shadow Copy Service Metadata](https://www.nutanix.dev/2025/01/14/nutanix-v4-disaster-recovery-api-series-part-1-volume-shadow-copy-service-metadata/ "Nutanix v4 Disaster Recovery API Series Part 1: Volume Shadow Copy Service Metadata") 6 | - [Nutanix v4 Disaster Recovery API Series Part 2: Changed Blocks Tracking (CBT) and Changed Regions Tracking (CRT)](https://www.nutanix.dev/2025/01/15/nutanix-v4-disaster-recovery-api-series-part-2-changed-blocks-tracking-cbt-and-changed-regions-tracking-crt/ "Nutanix v4 Disaster Recovery API Series Part 2: Changed Blocks Tracking (CBT) and Changed Regions Tracking (CRT)") 7 | -------------------------------------------------------------------------------- /python/v4api_sdk/dr/requirements.txt: -------------------------------------------------------------------------------- 1 | ntnx_dataprotection_py_client==4.0.1 2 | -------------------------------------------------------------------------------- /python/v4api_sdk/dr/vss_api_code.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | 4 | # Import ntnx dataprotection api libraries. 5 | import ntnx_dataprotection_py_client 6 | 7 | 8 | # Discover cluster specific libraries. 9 | from ntnx_dataprotection_py_client.models.dataprotection.v4.content.ClusterDiscoverSpec import ClusterDiscoverSpec 10 | from ntnx_dataprotection_py_client.models.dataprotection.v4.common.ClusterInfo import ClusterInfo 11 | from ntnx_dataprotection_py_client.models.dataprotection.v4.content.ClusterDiscoverOperation import ClusterDiscoverOperation 12 | from ntnx_dataprotection_py_client.models.dataprotection.v4.content.GetVssMetadataClusterDiscoverSpec import GetVssMetadataClusterDiscoverSpec 13 | 14 | 15 | def get_pc_client_config(): 16 | # Configure the client. 17 | config = ntnx_dataprotection_py_client.Configuration() 18 | # IPv4/IPv6 address or FQDN of the cluster 19 | config.host = sys.argv[1] 20 | # Port to which to connect to. 21 | config.port = 9440 22 | # Max retry attempts while reconnecting on a loss of connection 23 | config.max_retry_attempts = 3 24 | # Backoff factor to use during retry attempts 25 | config.backoff_factor = 3 26 | # UserName to connect to the cluster 27 | config.username = 28 | # Password to connect to the cluster 29 | config.password = 30 | return config 31 | 32 | 33 | def get_pe_client_config(target_cluster_ip): 34 | # Configure the client. 35 | config = ntnx_dataprotection_py_client.Configuration() 36 | # IPv4/IPv6 address or FQDN of the cluster 37 | config.host = target_cluster_ip 38 | # Port to which to connect to. 39 | config.port = 9440 40 | # Max retry attempts while reconnecting on a loss of connection 41 | config.max_retry_attempts = 3 42 | # Backoff factor to use during retry attempts 43 | config.backoff_factor = 3 44 | return config 45 | 46 | 47 | def prepare_discover_cluster_request_body(vmRecoveryPointExtId=None): 48 | # Discover cluster body model. 49 | clusterDiscoverSpec = ClusterDiscoverSpec() 50 | # Set the operation for which you want to send the discover cluster request. 51 | clusterDiscoverSpec.operation = ClusterDiscoverOperation.GET_VSS_METADATA 52 | # prepare GET_VSS_METADATA spec body. 53 | vss_spec = GetVssMetadataClusterDiscoverSpec(vm_recovery_point_ext_id=vmRecoveryPointExtId) 54 | # Set the vss spec in cluster discover spec body. 55 | clusterDiscoverSpec.spec = vss_spec 56 | return clusterDiscoverSpec 57 | 58 | 59 | def get_pc_recovery_point_api_client(): 60 | # Get the client configuration. 61 | pc_client_config = get_pc_client_config() 62 | # Intialize the PC ApiClient. 63 | pc_client = ntnx_dataprotection_py_client.ApiClient(configuration=pc_client_config) 64 | pc_recovery_points_api = ntnx_dataprotection_py_client.RecoveryPointsApi(api_client=pc_client) 65 | return pc_recovery_points_api 66 | 67 | def get_pe_recovery_point_api_client(target_cluster_ip, certificate=None): 68 | # Get the client configuration. 69 | pe_client_config = get_pe_client_config(target_cluster_ip) 70 | # Intialize the PC ApiClient. 71 | pe_client = ntnx_dataprotection_py_client.ApiClient(configuration=pe_client_config) 72 | # Set the cookie header. 73 | igw_header = "NTNX_IGW_SESSION={}".format(certificate) 74 | pe_client.add_default_header("cookie", igw_header) 75 | pe_recovery_points_api = ntnx_dataprotection_py_client.RecoveryPointsApi(api_client=pe_client) 76 | return pe_recovery_points_api 77 | 78 | if __name__ == "__main__": 79 | recovery_point_ext_id = sys.argv[2] 80 | vm_recovery_point_ext_id = sys.argv[3] 81 | clusterDiscoverSpec = prepare_discover_cluster_request_body(vmRecoveryPointExtId=vm_recovery_point_ext_id) 82 | pe_auth_certificate = None 83 | try: 84 | pc_rp_api_client = get_pc_recovery_point_api_client() 85 | pc_api_response = pc_rp_api_client.discover_cluster_for_recovery_point_id(extId=recovery_point_ext_id, body=clusterDiscoverSpec) 86 | print(pc_api_response) 87 | pe_auth_certificate = pc_api_response.data.jwt_token 88 | except ntnx_dataprotection_py_client.rest.ApiException as e: 89 | print(e) 90 | 91 | # PE API call. 92 | try: 93 | target_cluster_ip = pc_api_response.data.cluster_ip.ipv4.value 94 | pe_rp_api_client = get_pe_recovery_point_api_client(target_cluster_ip, certificate=pe_auth_certificate) 95 | pe_api_response = pe_rp_api_client.get_vss_metadata_by_vm_recovery_point_id(recoveryPointExtId=recovery_point_ext_id,vmRecoveryPointExtId=vm_recovery_point_ext_id) 96 | print(pe_api_response) 97 | except ntnx_dataprotection_py_client.rest.ApiException as e: 98 | print(e) 99 | -------------------------------------------------------------------------------- /python/v4api_sdk/get_vm_stats_sdk.py: -------------------------------------------------------------------------------- 1 | """ 2 | Use the Nutanix v4 API SDKs to get VM stats 3 | Requires Prism Central 2024.3.1 or later and AOS 7.0 or later 4 | Author: Chris Rasmussen, Senior Technical Marketing Engineer, Nutanix 5 | Date: May 2025 6 | """ 7 | 8 | # pylint: disable=line-too-long 9 | 10 | from datetime import datetime, timedelta 11 | import sys 12 | import urllib3 13 | 14 | from ntnx_vmm_py_client.rest import ApiException as VMMException 15 | from ntnx_vmm_py_client import DownSamplingOperator 16 | 17 | # utilities functions and classes e.g. environment management 18 | from tme.utils import Utils 19 | 20 | # functions and classes for Prism Central connection management 21 | from tme.apiclient import ApiClient 22 | 23 | 24 | def main(): 25 | """ 26 | suppress warnings about insecure connections 27 | please consider the security implications before 28 | doing this in a production environment 29 | """ 30 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 31 | 32 | utils = Utils() 33 | config = utils.get_environment() 34 | 35 | try: 36 | print(utils.printc("SDK", "Collecting environment details ...", "magenta")) # noqa 37 | 38 | # setup the instance of our ApiClient classes 39 | # these handle all Prism Central connections and provides 40 | # access to the chosen namespace's APIs, when required 41 | # this demo requires the following namespaces: 42 | # ntnx_vmm_py_client 43 | vmm_client = ApiClient(config=config, sdk_module="ntnx_vmm_py_client") 44 | # with the vmm client setup, specify the Nutanix v4 API we want to use 45 | # this section requires use of the VmApi 46 | vmm_instance = vmm_client.imported_module.api.VmApi( 47 | api_client=vmm_client.api_client 48 | ) 49 | 50 | # get a list of VMs, filtered by name 51 | vm_name = "cr-tools-server-dsl" 52 | vm_list = vmm_instance.list_vms(async_req=False, _filter=f"name eq '{vm_name}'") # noqa 53 | 54 | # make sure at least 1 VM was found 55 | if not vm_list.data: 56 | print(utils.printc("ERR", "No VMs found. Exiting ...", "red")) 57 | sys.exit() 58 | else: 59 | print(utils.printc("INFO", "Matching VM found. Continuing ...", "blue")) # noqa 60 | 61 | print( 62 | utils.printc( 63 | "RESP", 64 | "This script is for demo purposes only and has found the following VM details.", 65 | "yellow", 66 | ) 67 | ) # noqa 68 | print(f" VM ext_id: {vm_list.data[0].ext_id}") 69 | print(f" VM name: {vm_list.data[0].name}") 70 | confirm_continue = utils.confirm(" Continue demo using these details?") # noqa 71 | 72 | if confirm_continue: 73 | print(utils.printc("INFO", "Continuing ...", "blue")) 74 | else: 75 | print(utils.printc("INFO", "Exiting ...", "magenta")) 76 | sys.exit() 77 | 78 | ext_id = vm_list.data[0].ext_id 79 | 80 | stats_instance = vmm_client.imported_module.api.StatsApi( 81 | api_client=vmm_client.api_client 82 | ) 83 | 84 | # setup the stats request parameters 85 | # this example is AEST 86 | 87 | # start time is "now" minus 5 minutes 88 | # default in this demo is UTC+10 i.e. AEST 89 | start_time = (datetime.now() - timedelta(minutes=5)).strftime("%Y-%m-%dT%H:%M:%S+10:00") 90 | # end time is "now" 91 | end_time = datetime.now().strftime("%Y-%m-%dT%H:%M:%S+10:00") 92 | 93 | start_object = datetime.fromisoformat(start_time) 94 | end_object = datetime.fromisoformat(end_time) 95 | 96 | sampling_interval = 30 97 | select = "stats/hypervisorCpuUsagePpm,extId" 98 | stat_type = DownSamplingOperator.AVG 99 | 100 | print( 101 | utils.printc( 102 | "INFO", 103 | "This demo script will use the following spec:", 104 | "blue", 105 | ) 106 | ) 107 | print(f" Start time: {start_time}") 108 | print(f" End time: {end_time}") 109 | print(" VM extId will be included in the response") 110 | print(" 5 minute reporting period") 111 | print(" 30 second reporting interval") 112 | print(" AVG downsampling operator type") 113 | 114 | print(utils.printc("INFO", "Retrieving VM stats ...", "blue")) 115 | stats = stats_instance.get_vm_stats_by_id( 116 | ext_id, 117 | _startTime=start_object, 118 | _endTime=end_object, 119 | _samplingInterval=sampling_interval, 120 | _statType=stat_type, 121 | _select=select, 122 | ) 123 | 124 | print(utils.printc("INFO", "VM stats request completed.", "blue")) 125 | display_stats = utils.confirm( 126 | utils.printc( 127 | "INPUT", 128 | f"{len(stats.data.stats)} stats object(s) found. Display response now? Note: Stats responses can be very large.", 129 | "blue", 130 | ) 131 | ) # noqa 132 | 133 | if display_stats: 134 | print(stats.data) 135 | # example of showing the first hypervisor CPU usage statistic only 136 | # commented for demo purposes 137 | # print(stats.data.stats[0].hypervisor_cpu_usage_ppm) 138 | 139 | except VMMException as vmm_exception: 140 | print( 141 | f"Unable to authenticate using the supplied credentials. \ 142 | Check your username and/or password, then try again. \ 143 | Exception details: {vmm_exception}" 144 | ) 145 | 146 | 147 | if __name__ == "__main__": 148 | main() 149 | -------------------------------------------------------------------------------- /python/v4api_sdk/lcm_updates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/v4api_sdk/lcm_updates.png -------------------------------------------------------------------------------- /python/v4api_sdk/lcm_updates_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/v4api_sdk/lcm_updates_v2.png -------------------------------------------------------------------------------- /python/v4api_sdk/list_images_sdk.py: -------------------------------------------------------------------------------- 1 | """ 2 | Use the Nutanix v4 API SDKs to request and parse a list of all available images 3 | """ 4 | 5 | import getpass 6 | import argparse 7 | import urllib3 8 | 9 | import ntnx_vmm_py_client 10 | from ntnx_vmm_py_client import ApiClient as VMMClient 11 | from ntnx_vmm_py_client import Configuration as VMMConfiguration 12 | from ntnx_vmm_py_client.rest import ApiException as VMMException 13 | 14 | """ 15 | suppress warnings about insecure connections 16 | please consider the security implications before 17 | doing this in a production environment 18 | """ 19 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 20 | 21 | """ 22 | setup the command line parameters 23 | for this example only two parameters are required 24 | - the Prism Central IP address or FQDN 25 | - the Prism Central username; the script will prompt for the user's password 26 | so that it never needs to be stored in plain text 27 | """ 28 | parser = argparse.ArgumentParser() 29 | parser.add_argument("pc_ip", help="Prism Central IP address or FQDN") 30 | parser.add_argument("username", help="Prism Central username") 31 | args = parser.parse_args() 32 | 33 | # get the cluster password 34 | cluster_password = getpass.getpass( 35 | prompt="Please enter your Prism Central \ 36 | password: ", 37 | stream=None, 38 | ) 39 | 40 | pc_ip = args.pc_ip 41 | username = args.username 42 | 43 | # make sure the user enters a password 44 | if not cluster_password: 45 | while not cluster_password: 46 | print( 47 | "Password cannot be empty. \ 48 | Please enter a password or Ctrl-C/Ctrl-D to exit." 49 | ) 50 | cluster_password = getpass.getpass( 51 | prompt="Please enter your Prism Central password: ", stream=None 52 | ) 53 | 54 | if __name__ == "__main__": 55 | config = VMMConfiguration() 56 | config.host = pc_ip 57 | config.username = username 58 | config.password = cluster_password 59 | # known issue in pc.2022.6 that ignores this setting 60 | config.max_retry_attempts = 1 61 | config.backoff_factor = 3 62 | config.verify_ssl = False 63 | try: 64 | api_client = VMMClient(configuration=config) 65 | api_instance = ntnx_vmm_py_client.api.ImagesApi(api_client=api_client) 66 | # without filters 67 | images_list_no_filters = api_instance.list_images() 68 | if images_list_no_filters.metadata.total_available_results > 0: 69 | print( 70 | f"Images found without any filters: {len(images_list_no_filters.data)}" 71 | ) 72 | else: 73 | print("No images found.") 74 | # with filters 75 | images_list_with_filter = api_instance.list_images( 76 | _filter="startswith(name, 'A')" 77 | ) 78 | if images_list_with_filter.metadata.total_available_results > 0: 79 | print( 80 | f"Images with name beginning with 'A': {len(images_list_with_filter.data)}" 81 | ) 82 | else: 83 | print('No images found with name starting with "U".') 84 | images_list_matches = api_instance.list_images(_filter="name in ('scenario01')") 85 | if images_list_matches.metadata.total_available_results > 0: 86 | print(f"Images found with names in list: {len(images_list_matches.data)}") 87 | else: 88 | print("No images found matching this filter list.") 89 | # using _orderby 90 | images_list_orderby_name = api_instance.list_images(_orderby="name asc") 91 | if images_list_orderby_name.metadata.total_available_results > 0: 92 | print("\nImages found in PC instance, ordered by name, ascending:") 93 | for image in images_list_orderby_name.data: 94 | print(f"Image name: {image.name} ({image.ext_id})") 95 | else: 96 | print("No images found while using order by name filter.") 97 | images_list_orderby_size = api_instance.list_images(_orderby="sizeBytes desc") 98 | if images_list_orderby_size.metadata.total_available_results > 0: 99 | print("\nImages found in PC instance, ordered by size, descending:") 100 | for image in images_list_orderby_size.data: 101 | print(f"Image name: {image.name}, size (bytes): {image.size_bytes}") 102 | else: 103 | print("No images found while using order by size filter.") 104 | except VMMException as e: 105 | print( 106 | f"Unable to authenticate using the supplied credentials. \ 107 | Please check your username and/or password, then try again. \ 108 | Exception details: {e}" 109 | ) 110 | -------------------------------------------------------------------------------- /python/v4api_sdk/requirements.txt: -------------------------------------------------------------------------------- 1 | requests==2.32.2 2 | ruff==0.1.15 3 | ntnx_vmm_py_client==4.0.1 4 | ntnx_lifecycle_py_client==4.0.1 5 | ntnx_prism_py_client==4.0.1 6 | ntnx_clustermgmt_py_client==4.0.1 7 | ntnx_aiops_py_client==4.0.1 8 | ntnx_networking_py_client==4.0.1 9 | ntnx_microseg_py_client==4.0.1 10 | ntnx_iam_py_client==4.0.1 11 | ntnx_opsmgmt_py_client==4.0.1 12 | termcolor==2.5.0 -------------------------------------------------------------------------------- /python/v4api_sdk/screenshot_batch_create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/v4api_sdk/screenshot_batch_create.png -------------------------------------------------------------------------------- /python/v4api_sdk/screenshot_batch_modify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/v4api_sdk/screenshot_batch_modify.png -------------------------------------------------------------------------------- /python/v4api_sdk/screenshot_create_cats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/v4api_sdk/screenshot_create_cats.png -------------------------------------------------------------------------------- /python/v4api_sdk/screenshot_create_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/v4api_sdk/screenshot_create_image.png -------------------------------------------------------------------------------- /python/v4api_sdk/screenshot_create_nsp1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/v4api_sdk/screenshot_create_nsp1.png -------------------------------------------------------------------------------- /python/v4api_sdk/screenshot_create_nsp2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/v4api_sdk/screenshot_create_nsp2.png -------------------------------------------------------------------------------- /python/v4api_sdk/screenshot_create_subnet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/v4api_sdk/screenshot_create_subnet.png -------------------------------------------------------------------------------- /python/v4api_sdk/screenshot_create_vm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/v4api_sdk/screenshot_create_vm.png -------------------------------------------------------------------------------- /python/v4api_sdk/screenshot_list_images.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/v4api_sdk/screenshot_list_images.png -------------------------------------------------------------------------------- /python/v4api_sdk/screenshot_update_image_etag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/v4api_sdk/screenshot_update_image_etag.png -------------------------------------------------------------------------------- /python/v4api_sdk/startup-example.json: -------------------------------------------------------------------------------- 1 | { 2 | "pc_ip": "", 3 | "pc_username": "", 4 | "pc_password": "", 5 | "cluster_name": "" 6 | } 7 | -------------------------------------------------------------------------------- /python/v4api_sdk/startup.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import urllib3 3 | import uuid 4 | import os 5 | from requests.auth import HTTPBasicAuth 6 | import json 7 | from dataclasses import dataclass 8 | 9 | 10 | import ntnx_lifecycle_py_client 11 | from ntnx_lifecycle_py_client import ApiClient as LCMClient 12 | from ntnx_lifecycle_py_client import Configuration as LCMConfiguration 13 | 14 | from ntnx_prism_py_client import ApiClient as PrismClient 15 | from ntnx_prism_py_client import Configuration as PrismConfiguration 16 | 17 | import ntnx_clustermgmt_py_client 18 | from ntnx_clustermgmt_py_client import ApiClient as ClusterClient 19 | from ntnx_clustermgmt_py_client import Configuration as ClusterConfiguration 20 | 21 | import ntnx_vmm_py_client 22 | from ntnx_vmm_py_client import ApiClient as VMMClient 23 | from ntnx_vmm_py_client import Configuration as VMMConfiguration 24 | 25 | from ntnx_microseg_py_client import ApiClient as MicrosegClient 26 | from ntnx_microseg_py_client import Configuration as MicrosegConfiguration 27 | 28 | from ntnx_lifecycle_py_client.models.lifecycle.v4.resources.RecommendationSpec import ( 29 | RecommendationSpec, 30 | ) 31 | 32 | 33 | @dataclass 34 | class Config: 35 | """ 36 | dataclass to hold configuration for each script run 37 | nice and modular 38 | """ 39 | 40 | pc_ip: str 41 | pc_username: str 42 | pc_password: str 43 | cluster_name: str 44 | 45 | 46 | def main(): 47 | # load the configuration 48 | try: 49 | if os.path.exists("./startup.json"): 50 | with open("./startup.json", "r", encoding="utf-8") as config_file: 51 | config_json = json.loads(config_file.read()) 52 | else: 53 | print("Configuration file not found.") 54 | except json.decoder.JSONDecodeError as config_error: 55 | print(f"Unable to load configuration: {config_error}") 56 | 57 | # assign variables based on config loaded from JSON file 58 | user_config = Config( 59 | pc_ip=config_json["pc_ip"], 60 | pc_username=config_json["pc_username"], 61 | pc_password=config_json["pc_password"], 62 | cluster_name=config_json["cluster_name"], 63 | ) 64 | 65 | # create HTTPBasicAuth instance, for use cases requiring basic auth vs SDK auth 66 | prism_central_auth = HTTPBasicAuth(user_config.pc_username, user_config.pc_password) 67 | 68 | # set to true if you have a connection to Prism Central 69 | live = True 70 | 71 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 72 | 73 | lcm_config = LCMConfiguration() 74 | prism_config = PrismConfiguration() 75 | vmm_config = VMMConfiguration() 76 | cluster_config = ClusterConfiguration() 77 | microseg_config = MicrosegConfiguration() 78 | 79 | for config in [ 80 | lcm_config, 81 | prism_config, 82 | vmm_config, 83 | cluster_config, 84 | microseg_config, 85 | ]: 86 | config.host = user_config.pc_ip 87 | config.username = user_config.pc_username 88 | config.password = user_config.pc_password 89 | config.verify_ssl = False 90 | 91 | lcm_client = LCMClient(configuration=lcm_config) 92 | prism_client = PrismClient(configuration=prism_config) 93 | vmm_client = VMMClient(configuration=vmm_config) 94 | cluster_client = ClusterClient(configuration=cluster_config) 95 | microseg_client = MicrosegClient(configuration=microseg_config) 96 | 97 | for client in [ 98 | lcm_client, 99 | prism_client, 100 | vmm_client, 101 | cluster_client, 102 | microseg_client, 103 | ]: 104 | client.add_default_header( 105 | header_name="Accept-Encoding", header_value="gzip, deflate, br" 106 | ) 107 | 108 | rec_spec = RecommendationSpec() 109 | rec_spec.entity_types = ["software"] 110 | 111 | lcm_instance = ntnx_lifecycle_py_client.api.RecommendationsApi( 112 | api_client=lcm_client 113 | ) 114 | 115 | cluster_instance = ntnx_clustermgmt_py_client.api.ClustersApi( 116 | api_client=cluster_client 117 | ) 118 | if live: 119 | try: 120 | cluster_list = cluster_instance.list_clusters(async_req=False) 121 | cluster = [ 122 | x for x in cluster_list.data if x.name == user_config.cluster_name 123 | ] 124 | cluster_extid = cluster[0].ext_id 125 | except ntnx_clustermgmt_py_client.rest.ApiException as ex: 126 | print(type(ex)) 127 | sys.exit() 128 | else: 129 | # this will mean actions requiring a cluster extid e.g. image creation 130 | # will fail 131 | cluster_extid = "" 132 | print("\n*** Warning: live is set to False. Expect errors ...\n") 133 | 134 | unique_id = uuid.uuid1() 135 | 136 | new_image = ntnx_vmm_py_client.models.vmm.v4.content.Image.Image() 137 | new_image.name = f"image_{unique_id}" 138 | new_image.desc = "no desc" 139 | new_image.type = "DISK_IMAGE" 140 | image_source = ntnx_vmm_py_client.models.vmm.v4.content.UrlSource.UrlSource() 141 | image_source.url = "https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-2003.qcow2" 142 | image_source.allow_insecure = False 143 | new_image.source = image_source 144 | image_cluster = ( 145 | ntnx_vmm_py_client.models.vmm.v4.ahv.config.ClusterReference.ClusterReference() 146 | ) 147 | image_cluster.ext_id = cluster_extid 148 | new_image.initial_cluster_locations = [image_cluster] 149 | 150 | vmm_instance = ntnx_vmm_py_client.api.ImagesApi(api_client=vmm_client) 151 | 152 | # image_create = vmm_instance.create_image(async_req=False, body=new_image) 153 | 154 | 155 | if __name__ == "__main__": 156 | main() 157 | -------------------------------------------------------------------------------- /python/v4api_sdk/subnet_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "UVM", 3 | "description": "User VMS only, no CVMs or Nutanix Products", 4 | "subnet_type": "VLAN", 5 | "network_id": 406, 6 | "virtual_switch_reference": "ef6defb7-bfb2-4c08-9ac7-e2cf195077ec", 7 | "is_external": false, 8 | "is_advanced_networking": true, 9 | "subnet_prefix": 25, 10 | "subnet_ip_address": "10.38.141.0", 11 | "subnet_ip_prefix": 32, 12 | "dhcp": { 13 | "dns_servers": [ 14 | { 15 | "prefix_length": 32, 16 | "ip_address": "10.42.194.10" 17 | }, 18 | { 19 | "prefix_length": 32, 20 | "ip_address": "10.42.196.10" 21 | } 22 | ], 23 | "dhcp_server": { 24 | "prefix_length": 32, 25 | "ip_address": "10.38.141.126" 26 | }, 27 | "dhcp_pool": { 28 | "start_ip": { 29 | "prefix_length": 32, 30 | "ip_address": "10.38.141.20" 31 | }, 32 | "end_ip": { 33 | "prefix_length": 32, 34 | "ip_address": "10.38.141.125" 35 | } 36 | } 37 | }, 38 | "gateway": { 39 | "prefix_length": 32, 40 | "ip_address": "10.38.141.1" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /python/v4api_sdk/tme/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/python/v4api_sdk/tme/__init__.py -------------------------------------------------------------------------------- /python/v4api_sdk/tme/apiclient.py: -------------------------------------------------------------------------------- 1 | """ 2 | Simple module to allow function re-use across Nutanix 3 | v4 SDK code samples 4 | 5 | Requires Prism Central 2024.3 or later, AOS 7.0 or later 6 | """ 7 | 8 | import urllib3 9 | from dataclasses import dataclass 10 | 11 | from .utils import Config 12 | 13 | class ApiClient: 14 | """ 15 | class to Nutanix v4 API and SDK connections 16 | """ 17 | 18 | def __init__(self, config: Config, sdk_module: str = ""): 19 | """ 20 | class constructor 21 | """ 22 | 23 | # disable insecure connection warnings 24 | # consider the security implications before doing this in production 25 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 26 | 27 | # import the specified SDK module 28 | self.imported_module = __import__(sdk_module) 29 | 30 | # setup the connection information 31 | self.configuration = self.imported_module.Configuration() 32 | self.configuration.host = config.pc_ip 33 | self.configuration.port = "9440" 34 | self.configuration.username = config.pc_username 35 | self.configuration.password = config.pc_password 36 | self.configuration.verify_ssl = False 37 | 38 | # setup the API client instance 39 | self.api_client = self.imported_module.ApiClient(configuration=self.configuration) 40 | -------------------------------------------------------------------------------- /python/v4api_sdk/tme/test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from utils import Utils 3 | 4 | class TestUtils(unittest.TestCase): 5 | 6 | def test_confirm_yes(self): 7 | utils = Utils() 8 | self.assertEqual(utils.confirm("Enter yes:"), True) 9 | 10 | def test_confirm_no(self): 11 | utils = Utils() 12 | self.assertEqual(utils.confirm("Enter no:"), False) 13 | 14 | if __name__ == "__main__": 15 | unittest.main() 16 | -------------------------------------------------------------------------------- /python/v4api_sdk/update_image_etag_sdk.py: -------------------------------------------------------------------------------- 1 | """ 2 | Use the Nutanix v4 Python SDK to update a Prism Central image 3 | 4 | Requires Prism Central 2024.1 or later and AOS 6.8 or later 5 | """ 6 | 7 | import getpass 8 | import argparse 9 | import urllib3 10 | import sys 11 | 12 | import ntnx_vmm_py_client 13 | from ntnx_vmm_py_client import ApiClient as VMMClient 14 | from ntnx_vmm_py_client import Configuration as VMMConfiguration 15 | from ntnx_vmm_py_client.rest import ApiException as VMMException 16 | 17 | from ntnx_prism_py_client import ApiClient as PrismClient 18 | from ntnx_prism_py_client import Configuration as PrismConfiguration 19 | 20 | from tme.utils import Utils 21 | 22 | """ 23 | suppress warnings about insecure connections 24 | consider the security implications before 25 | doing this in a production environment 26 | """ 27 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 28 | 29 | """ 30 | setup the command line parameters 31 | for this example only two parameters are required 32 | - the Prism Central IP address or FQDN 33 | - the Prism Central username; the script will prompt for the user's password 34 | so that it never needs to be stored in plain text 35 | """ 36 | parser = argparse.ArgumentParser() 37 | parser.add_argument("pc_ip", help="Prism Central IP address or FQDN") 38 | parser.add_argument("username", help="Prism Central username") 39 | args = parser.parse_args() 40 | 41 | # get the cluster password 42 | cluster_password = getpass.getpass( 43 | prompt="Please enter your Prism Central \ 44 | password: ", 45 | stream=None, 46 | ) 47 | 48 | pc_ip = args.pc_ip 49 | username = args.username 50 | 51 | # create utils instance for re-use later 52 | utils = Utils(pc_ip=pc_ip, username=username, password=cluster_password) 53 | 54 | # make sure the user enters a password 55 | if not cluster_password: 56 | while not cluster_password: 57 | print( 58 | "Password cannot be empty. \ 59 | Please enter a password or Ctrl-C/Ctrl-D to exit." 60 | ) 61 | cluster_password = getpass.getpass( 62 | prompt="Please enter your Prism Central password: ", stream=None 63 | ) 64 | 65 | if __name__ == "__main__": 66 | vmm_config = VMMConfiguration() 67 | prism_config = PrismConfiguration() 68 | 69 | for config in [vmm_config, prism_config]: 70 | config.host = pc_ip 71 | config.username = username 72 | config.password = cluster_password 73 | config.verify_ssl = False 74 | 75 | try: 76 | vmm_client = VMMClient(configuration=vmm_config) 77 | prism_client = PrismClient(configuration=prism_config) 78 | 79 | for client in [vmm_client, prism_client]: 80 | client.add_default_header( 81 | header_name="Accept-Encoding", header_value="gzip, deflate, br" 82 | ) 83 | 84 | vmm_instance = ntnx_vmm_py_client.api.ImagesApi(api_client=vmm_client) 85 | # get a list of existing images 86 | images_list = vmm_instance.list_images() 87 | if images_list.metadata.total_available_results > 0: 88 | print(f"Images found: {len(images_list.data)}") 89 | else: 90 | print("No images found.") 91 | sys.exit() 92 | 93 | # images have been found - update the first image in the list 94 | # to begin, we must retrieve that image's details 95 | print("Getting image ...") 96 | existing_image = vmm_instance.get_image_by_id(images_list.data[0].ext_id) 97 | 98 | # get the existing image's Etag 99 | # existing_image_etag = existing_image.data._reserved["ETag"] 100 | existing_image_etag = vmm_client.get_etag(existing_image) 101 | 102 | print(f"Working with image named {existing_image.data.name} ...") 103 | 104 | # create a new Prism Central image instance 105 | new_image = ntnx_vmm_py_client.models.vmm.v4.content.Image.Image() 106 | new_image.data = existing_image.data 107 | new_image.name = f"{existing_image.data.name} - Updated" 108 | new_image.type = existing_image.data.type 109 | 110 | # add the existing image's Etag as a new request header 111 | vmm_client.add_default_header( 112 | header_name="If-Match", header_value=existing_image_etag 113 | ) 114 | 115 | # update the image using a synchronous request (will wait until completion before returning) 116 | image_update = vmm_instance.update_image_by_id( 117 | body=new_image, extId=existing_image.data.ext_id, async_req=False 118 | ) 119 | task_extid = image_update.data.ext_id 120 | utils.monitor_task( 121 | task_ext_id=task_extid, 122 | task_name="Update image", 123 | pc_ip=pc_ip, 124 | username=username, 125 | password=cluster_password, 126 | poll_timeout=1, 127 | prefix="", 128 | ) 129 | 130 | except VMMException as e: 131 | print( 132 | f"Unable to authenticate using the supplied credentials. \ 133 | Please check your username and/or password, then try again. \ 134 | Exception details: {e}" 135 | ) 136 | -------------------------------------------------------------------------------- /python/v4api_sdk/userdata.yaml: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | users: 3 | - name: nutanix 4 | sudo: ['ALL=(ALL) NOPASSWD:ALL'] 5 | ssh-authorized-keys: 6 | - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQD486FNEscDkK4xqyvT5Syg+z2pjvJVp7ndBGcq3jhS8SFcelgsam2H3wHnV/ybH3dxc8a+Qd1RdACCqT5F+798BJj8XOjOAktI35yQd8Hh8jmUAHzmwh8QUGgFKnmsyI7aX3DLFmHrfp31LlHFuiNNCw9vW1V9klfTXDxuqwC243qgGNYqgeCbHMBHW21Ou+YhuZKAaacNuhgtaE5uw8kmCbg2KJTgxVSzcac3WU1Jih59fS5xIox6nEAGwQeo3jsBg2QT5oZLgBA4uo+ZHoxysbVaabd2XpEi+Pzf2NYJl6cYomAq2uNmieWBe0FPsBPPL8rmbG+qyg/EDfBWJuXjE5/eqDTbeb9/csRaXF94nhRgpMpBlcP7kVmeHmq4OeImbZbu9hWjO81VLss7L9MSaPK4Cl1ULXGO0NswtVqXlSz4tdSjpuYt4hSW1o2Hh58QMqoBmKAa+tw5PvpaMuVyRbklRFBmoBN9t6hb3tUDQwYLlO6FU73Ixhp8sPQelpcwtlh/SSAvncyEVOku65pJ8a0WfrmLCSIx4/KKbXH09eOY2T/U6BeFDXsorXFwN2/vaGJXB0HCMYI+RhG/vaj5BsJ4GL8iHBiXG7A7MEQel4j6UWzThFFZpBz+B2gs+aJrtf3pqYABWmLepn1rd049gCixyMnuPDo6+H7FD+GD6w== no-reply@acme.com 7 | lock-passwd: false 8 | passwd: $6$4guEcDvX$HBHMFKXp4x/Eutj0OW5JGC6f1toudbYs.q.WkvXGbUxUTzNcHawKRRwrPehIxSXHVc70jFOp3yb8yZgjGUuET. 9 | 10 | # note: the encoded password hash above is "nutanix/4u" (without the quotes) 11 | 12 | yum_repos: 13 | epel-release: 14 | baseurl: http://download.fedoraproject.org/pub/epel/7/$basearch 15 | enabled: true 16 | failovermethod: priority 17 | gpgcheck: true 18 | gpgkey: http://download.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7 19 | name: Extra Packages for Enterprise Linux 7 - Release 20 | 21 | package_update: true 22 | package_upgrade: true 23 | 24 | hostname: centos7-tools-vm 25 | 26 | packages: 27 | - gcc-c++ 28 | - make 29 | - unzip 30 | - bash-completion 31 | - python-pip 32 | - s3cmd 33 | - stress 34 | - awscli 35 | - ntp 36 | - ntpdate 37 | - nodejs 38 | - python36 39 | - python36-setuptools 40 | - jq 41 | - nginx 42 | 43 | runcmd: 44 | - npm install -g request express 45 | - systemctl stop firewalld 46 | - systemctl disable firewalld 47 | - /sbin/setenforce 0 48 | - sed -i -e 's/enforcing/disabled/g' /etc/selinux/config 49 | - /bin/python3.6 -m ensurepip 50 | - pip install -U pip 51 | - pip install boto3 python-magic 52 | - ntpdate -u -s 0.pool.ntp.org 1.pool.ntp.org 2.pool.ntp.org 3.pool.ntp.org 53 | - systemctl restart ntpd 54 | - systemctl enable nginx --now 55 | 56 | final_message: CentOS 7 Tools Machine setup successfully! 57 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Nutanix Developer Portal Code Samples 2 | 3 | A collection of code samples designed for distribution via the [Nutanix Developer Portal](https://www.nutanix.dev). 4 | 5 | **Note**: The structure of this repository changed on June 6th 2019. Please update any existing bookmarks you may have saved. 6 | 7 | Please feel free to use these for your own environments if you find them useful. 8 | 9 | ## Assumptions 10 | 11 | Detailed instructions on how to setup a development/testing environment are beyond the scope of this repo and the scripts contained within it. 12 | 13 | Each script language covered in this repository has an accompanying readme file that suggests how the environment should be setup, although individual preferences will nearly always override those suggestions. 14 | 15 | ## Sections 16 | 17 | - **python**: Python scripts based on Python >=3.7 18 | - **powershell**: Windows PowerShell scripts, based on PowerShell >= 5.1 19 | - **shell**: Bash scripts to run in a Linux terminal (please note that the Windows 10 Bash Shell has not been tested with these scripts!) 20 | - **csharp**: Single-file/script Microsoft C# applications, typically run in the console 21 | - **go** - Golang examples 22 | - **postman** - JSON payloads designed for use with the [Postman](https://getpostman.com) API development application 23 | - **blueprints** - NCM Self-Service blueprints 24 | 25 | ## License & Usage 26 | 27 | Please see the `LICENSE` file distributed with this repository. 28 | 29 | For full terms and conditions, please see [Nutanix Terms of Use](https://www.nutanix.com/legal/terms-of-use). 30 | 31 | ## Support & Disclaimer 32 | 33 | These scripts are *unofficial* and are not supported or actively maintained by Nutanix in any way. 34 | 35 | In addition, please also be advised that these scripts may contain code that does not follow best practices. Please check through each script to ensure the configuration suits your requirements. 36 | 37 | **Changes will be required before these scripts can be used in production environments.** 38 | 39 | See the `.disclaimer` file distributed with this repository. 40 | -------------------------------------------------------------------------------- /shell/batch_request_simple/batch_request_simple: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # shell script to demonstrate basic usage of the v3 batch API 4 | # requires the existence of a JSON-formatted file that contains: 5 | # 6 | # cluster/CVM IP 7 | # username 8 | # 9 | # this file must be named "batch_request_simple.json" and be formatted as follows: 10 | # 11 | # {"cluster_ip":"10.0.0.1","username":"admin"} 12 | 13 | JSON_FILE="./batch_request_simple.json" 14 | JSON_CONTENTS="`cat ${JSON_FILE}`" 15 | 16 | JQ=`command -v jq` 17 | CURL=`command -v curl` 18 | 19 | if [ "$JQ" = "" ] || [ "$CURL" = "" ]; then 20 | echo "jq command not found." 21 | else 22 | CLUSTER_IP=`echo -n $JSON_CONTENTS | jq -r ".cluster_ip"` 23 | USERNAME=`echo -n $JSON_CONTENTS | jq -r ".username"` 24 | 25 | # get the password from the user 26 | echo "Please enter your cluster password (will not be shown on screen):" 27 | read -s PASSWORD 28 | 29 | # generate the HTTP Basic Authorization header 30 | AUTH_HEADER="`echo -n $USERNAME:$PASSWORD | base64`" 31 | 32 | # submit the request 33 | curl --insecure -X POST \ 34 | --connect-timeout 5 \ 35 | https://$CLUSTER_IP:9440/api/nutanix/v3/batch \ 36 | -H "Accept: application/json" \ 37 | -H "Content-Type: application/json" \ 38 | -H "Authorization: Basic $AUTH_HEADER" \ 39 | -H "cache-control: no-cache" \ 40 | -d "{ 41 | \"action_on_failure\": \"CONTINUE\", 42 | \"execution_order\": \"SEQUENTIAL\", 43 | \"api_request_list\": [ 44 | { 45 | \"operation\": \"POST\", 46 | \"path_and_params\": \"/api/nutanix/v3/vms\", 47 | \"body\": { 48 | \"spec\": { 49 | \"name\": \"vm_from_batch\", 50 | \"resources\": {} 51 | }, 52 | \"metadata\": { 53 | \"kind\": \"vm\" 54 | } 55 | } 56 | }, 57 | { 58 | \"operation\": \"POST\", 59 | \"path_and_params\": \"/api/nutanix/v3/images\", 60 | \"body\": { 61 | \"spec\": { 62 | \"name\": \"image_from_batch\", 63 | \"resources\": { 64 | \"image_type\": \"DISK_IMAGE\", 65 | \"source_uri\": \"https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud-1905.qcow2\" 66 | }, 67 | \"description\": \"Image created via v3 API batch request\" 68 | }, 69 | \"api_version\": \"3.1.0\", 70 | \"metadata\": { 71 | \"kind\": \"image\", 72 | \"categories\": {}, 73 | \"name\": \"image_from_batch\" 74 | } 75 | } 76 | } 77 | ], 78 | \"api_version\": \"3.0\" 79 | }" 80 | 81 | fi -------------------------------------------------------------------------------- /shell/batch_request_simple/batch_request_simple.json: -------------------------------------------------------------------------------- 1 | {"cluster_ip":"10.0.0.1","username":"admin"} -------------------------------------------------------------------------------- /shell/batch_request_simple/readme.rst: -------------------------------------------------------------------------------- 1 | Bash Code Samples - batch_request_simple 2 | ######################################## 3 | 4 | This readme file is specifically for the **batch_request_simple** Bash script. 5 | 6 | The setup instructions are the same as all other Bash scripts in this repository. This file is provided as additional/supplemental information for this specific code sample. 7 | 8 | Please see the `main `_ page for general instructions. 9 | 10 | Script Usage 11 | ............ 12 | 13 | Once you have configured your system to run these scripts (see link above), the script can be run as follows. 14 | 15 | #. Edit **batch_request_simple.json** and change the Prism Central IP address to match your environment. 16 | 17 | .. code-block:: json 18 | 19 | "cluster_ip":"10.0.0.1" 20 | 21 | #. Edit **batch_request_simple.json** and edit the following variables to suit your requirements: 22 | 23 | .. code-block:: json 24 | 25 | "username":"admin" 26 | 27 | #. Edit **batch_request_simple** and edit the following variables to suit your requirements: 28 | 29 | .. code-block:: json 30 | 31 | \"name\": \"vm_from_batch\", 32 | 33 | .. code-block:: json 34 | 35 | \"name\": \"image_from_batch\" 36 | 37 | #. Execute the script: 38 | 39 | .. code-block:: bash 40 | 41 | ./batch_request_simple 42 | 43 | #. Verify the script ran successfully and that the batch API request returned HTTP code 202: 44 | 45 | .. figure:: script_output.png 46 | 47 | #. If you prefer, you can also check Prism Central to ensure the VM and image were both created successfully. -------------------------------------------------------------------------------- /shell/batch_request_simple/script_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/shell/batch_request_simple/script_output.png -------------------------------------------------------------------------------- /shell/create_vm_v3_basic/create_vm_v3_basic: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # shell script to create a basic VM using the Prism v3 REST API 4 | # requires the existence of a JSON-formatted file that contains: 5 | # 6 | # cluster/CVM IP 7 | # username 8 | # the name of the VM to be created 9 | # 10 | # this file must be named "create_vm_v3_basic.json" and be formatted as follows: 11 | # 12 | # {"cluster_ip":"10.0.0.1","username":"admin","vm_name":"BasicVMViaAPIv3"} 13 | 14 | JSON_FILE="./create_vm_v3_basic.json" 15 | JSON_CONTENTS="`cat ${JSON_FILE}`" 16 | 17 | JQ=`command -v jq` 18 | CURL=`command -v curl` 19 | 20 | if [ "$JQ" = "" ] || [ "$CURL" = "" ]; then 21 | echo "jq command not found." 22 | else 23 | CLUSTER_IP=`echo -n $JSON_CONTENTS | jq -r ".cluster_ip"` 24 | USERNAME=`echo -n $JSON_CONTENTS | jq -r ".username"` 25 | VM_NAME=`echo -n $JSON_CONTENTS | jq -r ".vm_name"` 26 | 27 | 28 | # get the password from the user 29 | echo "Please enter your cluster password (will not be shown on screen):" 30 | read -s PASSWORD 31 | 32 | # generate the HTTP Basic Authorization header 33 | AUTH_HEADER="`echo -n $USERNAME:$PASSWORD | base64`" 34 | 35 | # submit the request 36 | curl --insecure -X POST \ 37 | --connect-timeout 5 \ 38 | https://$CLUSTER_IP:9440/api/nutanix/v3/vms \ 39 | -H "Accept: application/json" \ 40 | -H "Content-Type: application/json" \ 41 | -H "Authorization: Basic $AUTH_HEADER" \ 42 | -H "cache-control: no-cache" \ 43 | -d "{ 44 | \"spec\":{ 45 | \"name\":\"$VM_NAME\", 46 | \"resources\":{ 47 | } 48 | }, 49 | \"metadata\":{ 50 | \"kind\":\"vm\" 51 | } 52 | }" 53 | 54 | fi -------------------------------------------------------------------------------- /shell/create_vm_v3_basic/create_vm_v3_basic.json: -------------------------------------------------------------------------------- 1 | {"cluster_ip":"10.0.0.1","username":"admin","vm_name":"BasicVMViaAPIv3"} -------------------------------------------------------------------------------- /shell/create_vm_v3_basic/readme.rst: -------------------------------------------------------------------------------- 1 | Bash Code Samples - create_vm_v3_basic 2 | ###################################### 3 | 4 | This readme file is specifically for the **create_vm_v3_basic** Bash script. 5 | 6 | The setup instructions are the same as all other Bash scripts in this repository. This file is provided as additional/supplemental information for this specific code sample. 7 | 8 | Please see the `main `_ page for general instructions. 9 | 10 | Script Usage 11 | ............ 12 | 13 | Once you have configured your system to run these scripts (see link above), the script can be run as follows. 14 | 15 | #. Edit **create_vm_v3_basic.json** and change the Prism Central IP address to match your environment. 16 | 17 | .. code-block:: json 18 | 19 | "cluster_ip":"10.0.0.1" 20 | 21 | #. Edit **create_vm_v3_basic.json** and edit the following variables to suit your requirements: 22 | 23 | .. code-block:: json 24 | 25 | "username":"admin" 26 | 27 | .. code-block:: json 28 | 29 | "vm_name":"BasicVMViaAPIv3" 30 | 31 | #. Execute the script: 32 | 33 | .. code-block:: bash 34 | 35 | ./create_vm_v3_basic 36 | 37 | #. Verify the script ran successfully and that the create VM API request returned HTTP code 202: 38 | 39 | .. figure:: script_output.png 40 | 41 | #. If you prefer, you can also check Prism Central to ensure the VM was created successfully. -------------------------------------------------------------------------------- /shell/create_vm_v3_basic/script_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/shell/create_vm_v3_basic/script_output.png -------------------------------------------------------------------------------- /shell/readme.rst: -------------------------------------------------------------------------------- 1 | Nutanix Developer Portal Code Samples - Bash Shell 2 | ################################################## 3 | 4 | To use the Bash Shell code samples, the following environment is recommended. 5 | 6 | - **curl** command available 7 | - **jq** (official documentation for `jq `_) 8 | - The accompanying JSON files from this repository (instructions and usage provided below). 9 | - A suitable editor, e.g. `Microsoft Visual Studio Code `_ for GUI editing or **vi** for terminal editing. 10 | - Access to a Nutanix Cluster for API v2.0 testing purposes. 11 | - Access to a Nutanix Prism Central instance for API v3 testing purposes. 12 | - Nutanix Community Edition is supported but may not always provide the exact same APIs as a "full" Nutanix cluster. 13 | 14 | .. note:: The readme below assumes you are creating the scripts from scratch and have not cloned the entire repository to your local system. 15 | 16 | Bash Shell Script Usage 17 | ....................... 18 | 19 | The provided bash shell scripts are designed to be standalone and can be run without additional dependencies beyond those provided above. 20 | 21 | The examples and screenshots below are from the **create_vm_v3_basic/create_vm_v3_basic** sample. This sample uses **create_vm_v3_basic.json** for the request parameters. 22 | 23 | #. Create a new file: 24 | 25 | .. code-block:: bash 26 | 27 | touch ~/create_vm_v3_basic 28 | 29 | #. Open the new file in vi: 30 | 31 | .. code-block:: bash 32 | 33 | vi ~/create_vm_v3_basic 34 | 35 | #. Have the code sample open in your browser. 36 | #. Copy the script source to your clipboard. 37 | #. Enable vi **INSERT** mode by pressing *i*. 38 | #. Paste the script source into vi by pressing Ctrl-Shift-V (typical for Linux terminals) or by pressing the middle mouse button, if available. 39 | 40 | .. note:: The copy and paste steps don't really need to be included as they will vary from system to system. They're included here for completeness' sake only. 41 | 42 | #. Exit vi **INSERT** mode by pressing **ESC**. 43 | #. Save the file by using the vi save and quit keystroke sequence: 44 | 45 | .. code-block: bash 46 | 47 | :wq 48 | 49 | #. Make the script executable: 50 | 51 | .. code-block: bash 52 | 53 | chmod u+x ~/create_vm_v3_basic 54 | 55 | #. Repeat steps 1-8 for the accompanying JSON file (the JSON file does not need to be executable). This file is required as it contains the parameters used for cURL request: 56 | 57 | - Copy the JSON source into the local clipboard, if using the example from the repository 58 | - In the terminal, create the JSON file and add the contents: 59 | 60 | .. code-block: bash 61 | 62 | touch ~/create_vm_v3_basic.json 63 | vi ~/create_vm_v3_basic.json 64 | 65 | - Press "i" for vi INSERT mode 66 | - Paste the JSON into vi 67 | - Press ESC to exit INSERT mode 68 | - Save the file by using the vi save and quit keystroke sequence ":wq", as before (without the quotes!) 69 | 70 | #. Run the script: 71 | 72 | .. code-block: bash 73 | 74 | ~/create_vm_v3_basic 75 | 76 | .. figure:: script_output.png 77 | 78 | #. Check the output to make sure the request has a state of **PENDING**. 79 | 80 | -------------------------------------------------------------------------------- /shell/script_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nutanixdev/code-samples/4ea47bc06481e32c5320816662808e5f6f37a687/shell/script_output.png --------------------------------------------------------------------------------