{"id":1005,"date":"2021-07-05T08:49:25","date_gmt":"2021-07-05T07:49:25","guid":{"rendered":"https:\/\/nine30.info\/?p=1005"},"modified":"2021-07-05T08:49:25","modified_gmt":"2021-07-05T07:49:25","slug":"consume-vra-saltstack-config-api-in-vra-extensibility","status":"publish","type":"post","link":"https:\/\/nine30.nxt70.com\/index.php\/2021\/07\/05\/consume-vra-saltstack-config-api-in-vra-extensibility\/","title":{"rendered":"Consume vRA SaltStack Config API in vRA Extensibility"},"content":{"rendered":"\n<p>These are the early days of the integration between vRealize Automation and vRealize Automation SaltStack Config (formerly know as SaltStack Enterprise) and some things are yet to come. For instance, today in the 8.4 version if you deprovision a VM in vRA the related Salt Minion key is not deleted in vRA SaltStack Config, this a typical situation where a vRA Extensibility elegantly solve the problem.<\/p>\n\n\n\n<p>In order to delete a Salt Minion key we have two options: using the Satl CLI or using the API (RaaS). We have APIs in products for integration and automation purposes and for this reason I picked the second option and here is what I did.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Brief intro about vRA SaltStack API<\/h2>\n\n\n\n<p>The API (RaaS) refers to the application server that vRA SaltStack Config clients connect to. These clients include the user interface component of SaltStack Config, properly configured Salt Masters, and other users of RaaS. RaaS is organized into modules (called \u201cresources\u201d) and functions (called \u201cmethods\u201d). In the API call <code>test.echo(\u2018hello, world\u2019)<\/code>, the resource is <code>test<\/code> and the method is <code>echo()<\/code>. Arguments can be passed to methods by position or by keyword.<\/p>\n\n\n\n<p>RaaS can be accessed in two ways: via an RPC client and via an HTTP (or HTTPS) bridge:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>RPC client: The programmatic RPC clients in the <code>sseapiclient<\/code> Python module work with Python version 2.7 and Python version 3.5 or later. The clients connect to vRA SaltStack Config via HTTP or HTTPS and authenticate. <\/li><li>HTTP Bridge: The HTTP (or HTTPS) bridge accepts JSON payloads POSTed to an endpoint exposed by vRA SaltStack Config, translates the payloads into RPC calls, then returns the result as JSON. The endpoint supports cookie-based authentication so that authentication credentials need to be passed only once per session. <\/li><\/ul>\n\n\n\n<p>For me, the RPC client proved to be definitely easier to use than the HTTP bridge.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Use SaltStack RPC in vRO Workflows<\/h2>\n\n\n\n<p>vRealize Automation since version 8.0 supports two types of extensibilities: vRO Workflows and ABX Actions, both supports Python (required by the RPC Client). In this post I am going to cover the vRO Workflow option.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Prepare you local dev environment<\/h3>\n\n\n\n<p>I tried this first on my Mac, but I had some issues and after some unsuccessful troubleshooting I opted to do the dev activity on an Ubuntu 20.04 box. You need to prepare your dev environment as follows:<\/p>\n\n\n\n<p>Have both Python 3 and Pip installed on your machine:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt update\nsudo apt install python3.8\nsudo apt install python3-pip<\/code><\/pre>\n\n\n\n<p>Create a directory to store all your artifacts, you can choose any name that works for you:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir \/p ~\/code\/vro_ssc_delete_minion<\/code><\/pre>\n\n\n\n<p>In your dev directory create a new directory named <code>lib<\/code>, the name have to be <code>lib<\/code> as in this directory you will install all the python script dependencies and vRO will look for this specific directory name for dependencies.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir ~\/code\/vro_ssc_delete_minion\/lib<\/code><\/pre>\n\n\n\n<p>Download from myvmware.com the API Client (Products and Account &gt; Products &gt; All Products and search for SaltStack keyword), as I am working with vRA 8.4 I got the following file <code>vRA_SSEAPE-8.4.0-py2.py3-none-any.whl<\/code>, once downloaded copy it in your dev folder and then install it the <code>lib<\/code> folder. As I was prompted to do so, I also installed the package named <code>six<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mv \/tmp\/SSEAPE-8.4.0-py2.py3-none-any.whl ~\/code\/vro_ssc_delete_minion\ncd ~\/code\/vro_ssc_delete_minion\npython3 -m pip install SSEAPE-8.4.0-py2.py3-none-any.whl -t .\/lib\npython3 -m pip install six -t .\/lib<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Create the package with your Python script<\/h3>\n\n\n\n<p>Add to your dev folder the Python script that uses the API Client, here below there is my script (you can do a better script for sure with error handling and so on). In my script there is just a thing to note: to delete a Minion from SaltStack Config you need to know its key, in my environment I use the machine IP address as the Minion key, this is provided as an input to the script. In my case I have this script in a file named <code>vro_ssc_delete_minion.py<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>from sseapiclient import APIClient\n\ndef handler(context, inputs):\n    outputs = {}\n    minion_key = inputs&#91;\"addresses\"]\n    msg = \"The address is: {0}!\".format(minion_key)\n\n    #connection info\n    ssc_host = 'https:\/\/vrassc.iberia.local'\n    username = '&lt;&lt;USERNAME&gt;&gt;'\n    password = '&lt;&lt;PASSWORD&gt;&gt;'\n    \n    client = APIClient(ssc_host, username, password, ssl_validate_cert=False)\n    client.minion.set_minion_key_state(state='delete', minions=&#91;'salt',minion_key])\n\n    outputs&#91;\"greetings\"]=msg\n\n    return outputs<\/code><\/pre>\n\n\n\n<p>Zip the content of the dev folder (you can remove the <code>SSEAPE-8.4.0-py2.py3-none-any.whl<\/code> file).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>zip -r ~\/vro_ssc_delete_minion.zip .<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"> Create the vRO Workflow<\/h3>\n\n\n\n<p>As first thing you need to create a new Action that uses your Python script. Pick an existing Module, or create a new one (my Module is named <code>com.vmware.iberia.se.saltapipy<\/code>), click the &#8220;New Action&#8221; button, provide Action names (in my case <code>deleteMinion<\/code>) and other details (I always recommend to add a description) and then select the Script tab. Here you have to choose Runtime = Python 3.7 and Type = Zip, at this point a &#8220;Import&#8221; button should appear allowing you to upload your zip package including your Python script. In the &#8220;Entry handler&#8221; text field you have to type the name of the script file without extension followed by a dot and the word &#8220;handler&#8221;, in my case I have <code>vro_ssc_delete_minion.handler<\/code>. At this stage you should be as in the situation in the picture below.<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-id=\"1048\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/07\/01.action.import.png\" alt=\"\" class=\"wp-image-1048\"\/><\/figure>\n<\/figure>\n\n\n\n<p>Now you have to hit on the &#8220;Add New Input button&#8221; and add a new string input named <code>minionKey<\/code>. Do not forget a description before clicking on the Create button.<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-id=\"1049\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/07\/01.action.input_.png\" alt=\"\" class=\"wp-image-1049\"\/><\/figure>\n<\/figure>\n\n\n\n<p>Now you can create your new Workflow that will be used into a extensibility subscription. Pick a folder in vRO Library and add a new workflow, give it a name (in my vase <code>IBSE SSC Delete Minion Key<\/code>) and other details (e.g. description). Add a input named <code>inputProperties<\/code> and Type <code>Properties<\/code>, add two variables: <code>minionKey<\/code> having Type <code>String<\/code> and <code>actionResult<\/code> having Type <code>Properties<\/code>. <\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-3 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-id=\"1050\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/07\/04.workflow.input_.png\" alt=\"\" class=\"wp-image-1050\"\/><\/figure>\n<\/figure>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-4 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-id=\"1051\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/07\/05.workflow.variables.png\" alt=\"\" class=\"wp-image-1051\"\/><\/figure>\n<\/figure>\n\n\n\n<p>My workflow schema is made up by 3 elements in this order: a Scriptable Task named <code>Read from vRA<\/code>, the action we just created named <code>deleteMinion<\/code> and a Scriptable Task named <code>Log Output<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-5 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-id=\"1052\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/07\/03.workflow.jpg\" alt=\"\" class=\"wp-image-1052\"\/><\/figure>\n<\/figure>\n\n\n\n<p>Details about the <code>Read from vRA<\/code> Scriptable Task: <\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Inputs: <code>inputProperties<\/code><\/li><li>Output: none. <\/li><li>The script is here below:<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>var pProperties = new Array();\nminionKey = \"\";\n\/\/Looking for 'minion ID key' as IP address of the VM (this is my specific setting)\npProperties = inputProperties.get(\"addresses\");\n\nif (pProperties&#91;0] != null &amp;&amp; pProperties&#91;0] != \"\"){\n    minionKey = String(pProperties&#91;0]);\n    System.log(\"Minion ID found: \" +minionKey);\n}<\/code><\/pre>\n\n\n\n<p>Details about the <code>deleteMinion<\/code> Action: <\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Inputs: <code>minionKey<\/code><\/li><li>Output: <code>actionResult<\/code><\/li><\/ul>\n\n\n\n<p>Details about the <code>Log Output<\/code> Scriptable Task: <\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Inputs: <code>actionResult<\/code><\/li><li>Output: none<\/li><li>The script is here below:<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>System.log(\"Action result: \"+actionResult&#91;\"greetings\"])<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Configure the Extensibility Subscription<\/h3>\n\n\n\n<p>In the vRealize Automation Cloud Assembly navigate to Extensibility tab and add a new Subscription with the following specifics:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Event topic: <code>Compute post removal<\/code><\/li><li>Condition: <code>event.data.blueprintId == '&lt;your clout template ID&gt;' <\/code><\/li><li>Action\/Workflow: <code>IBSE SSC Delete Minion Key<\/code><\/li><\/ul>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-6 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-id=\"1053\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/07\/06.subscription.png\" alt=\"\" class=\"wp-image-1053\"\/><\/figure>\n<\/figure>\n\n\n\n<p>In my case the subscription condition binds the execution of the extensibility for a specific Cloud Template (aka blueprint), in my case this Cloud Template deploys a VM and registers it as a Minion under vRA SaltStack Config. You may need to change this condition in case you need to execute the extensibility under different scenario.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>When a VM or an entire deployment based on the Cloud Template specified in the condition is deleted the extensibility is executed.<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-7 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-id=\"1054\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/07\/07.extensibility.workflow.run_.jpg\" alt=\"\" class=\"wp-image-1054\"\/><\/figure>\n<\/figure>\n\n\n\n<p>The workflow executes the SaltStack Config API and the Minion Key is deleted.<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-8 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-id=\"1055\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/07\/08.ssc_.api_.png\" alt=\"\" class=\"wp-image-1055\"\/><\/figure>\n<\/figure>\n","protected":false},"excerpt":{"rendered":"<p>These are the early days of the integration between vRealize Automation and vRealize Automation SaltStack Config (formerly know as SaltStack Enterprise) and some things are yet to come. For instance, today in the 8.4 version if you deprovision a VM in vRA the related Salt Minion key is not deleted in vRA SaltStack Config, this&hellip; <a class=\"more-link\" href=\"https:\/\/nine30.nxt70.com\/index.php\/2021\/07\/05\/consume-vra-saltstack-config-api-in-vra-extensibility\/\">Continue reading <span class=\"screen-reader-text\">Consume vRA SaltStack Config API in vRA Extensibility<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":788,"comment_status":"open","ping_status":"open","sticky":false,"template":"templates\/template-cover.php","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[4],"tags":[14,23,41,99,122,126,141,143,144,145,178,179,180,185,186],"class_list":["post-1005","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tech","tag-api","tag-automation","tag-configurationmanagement","tag-linux","tag-opensource","tag-oss","tag-python","tag-salt","tag-saltproject","tag-saltstack","tag-vmware","tag-vmware-cloud","tag-vmware-cloud-template","tag-vrealize","tag-vrealizeautomation","entry"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/posts\/1005","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/comments?post=1005"}],"version-history":[{"count":0,"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/posts\/1005\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/"}],"wp:attachment":[{"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/media?parent=1005"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/categories?post=1005"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/tags?post=1005"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}