{"id":1774,"date":"2023-02-22T09:30:00","date_gmt":"2023-02-22T14:30:00","guid":{"rendered":"https:\/\/enterpriseadmins.org\/blog\/?p=1774"},"modified":"2023-02-23T08:27:52","modified_gmt":"2023-02-23T13:27:52","slug":"getting-started-with-steampipe-io-to-query-vmware-vsphere","status":"publish","type":"post","link":"https:\/\/enterpriseadmins.org\/blog\/scripting\/getting-started-with-steampipe-io-to-query-vmware-vsphere\/","title":{"rendered":"Getting started with Steampipe.io to query VMware vSphere"},"content":{"rendered":"\n<p>I was recently listening to an episode of the <a href=\"https:\/\/unexploredterritory.tech\/\" data-type=\"URL\" data-id=\"https:\/\/unexploredterritory.tech\/\">Unexplored Territory podcast<\/a> (episode #023 &#8211; Introducing Oracle Cloud VMware Solution with <a href=\"https:\/\/twitter.com\/the_anykey\" data-type=\"URL\" data-id=\"https:\/\/twitter.com\/the_anykey\">Richard Garsthagen<\/a>).  At the end of each episode, the hosts ask the guest about a technology that should be explored.  The response to this question is the first time I heard about <a href=\"https:\/\/steampipe.io\/\" data-type=\"URL\" data-id=\"https:\/\/steampipe.io\/\">steampipe.io<\/a>.  I made a note to take a look at this open source project and wanted to share my notes on getting started.<\/p>\n\n\n\n<p>Steampipe is a SQL like query language for various plugin endpoints, such as AWS, Azure, CSV files, GCP, IMAP, LDAP, VMware vSphere, among others.  Plenty of other tools exist to query these endpoints, but this is the first I&#8217;ve seen where the exact same syntax can be used to query\/join all of them in one result set.<\/p>\n\n\n\n<p>To get started, I decided I would use the prebuilt container image (<a href=\"https:\/\/steampipe.io\/docs\/managing\/containers\">Using Containers | Documentation | Steampipe<\/a>).  The first step was to create a new directory to store some configuration files.  Also, as the processes in the container image run as a non-root user, I made this user (<code>uid 9193<\/code>) the owner of the folder.  Finally, as described in the documentation, I created an alias so that <code>sp<\/code> could be entered to interact with the container.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># create configuration folder\nmkdir -p \/data\/container\/steampipe\/sp\/config\n\n# make the non-root steampipe user the owner of this configuration folder\nchown 9193 \/data\/container\/steampipe\/sp\/config\n\n# alias the command\nalias sp=\"docker run \\\n  -it \\\n  --rm \\\n  --name steampipe \\\n  --mount type=bind,source=\/data\/container\/steampipe\/sp\/config,target=\/home\/steampipe\/.steampipe\/config  \\\n  --mount type=volume,source=steampipe_plugins,target=\/home\/steampipe\/.steampipe\/plugins   \\\n  turbot\/steampipe\"<\/code><\/pre>\n\n\n\n<p>Once the folder is defined and our alias is available, we are now able to install Steampipe plugins.  For my example, I&#8217;m only using the VMware vSphere and CSV file plugins, but you should explore the Steampipe documentation for other available options.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@lab-dock-14 &#91; \/data\/container\/steampipe\/sp ]# sp plugin install steampipe theapsgroup\/vsphere csv\n\nsteampipe            &#91;====================================================================] Done\ntheapsgroup\/vsphere  &#91;====================================================================] Done\ncsv                  &#91;====================================================================] Done\n\nInstalled plugin: csv@latest v0.5.0\nDocumentation:    https:\/\/hub.steampipe.io\/plugins\/turbot\/csv\n\nInstalled plugin: steampipe@latest v0.6.0\nDocumentation:    https:\/\/hub.steampipe.io\/plugins\/turbot\/steampipe\n\nInstalled plugin: vsphere@latest v0.1.3\nDocumentation:    https:\/\/hub.steampipe.io\/plugins\/theapsgroup\/vsphere<\/code><\/pre>\n\n\n\n<p>After installing the plugins, we should see a few <code>spc<\/code> files that were automatically configured.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@lab-dock-14 &#91; ~ ]# cd \/data\/container\/steampipe\/sp\/config\nroot@lab-dock-14 &#91; \/data\/container\/steampipe\/sp\/config ]# ls -lh\ntotal 16K\n-rw-r--r-- 1 9193 root 1.8K Feb 12 20:34 csv.spc\n-rwxr-xr-x 1 9193 root  971 Feb 12 20:34 default.spc\n-rw-r--r-- 1 9193 root   50 Feb 12 20:34 steampipe.spc\n-rw-r--r-- 1 9193 root  295 Feb 12 20:34 vsphere.spc<\/code><\/pre>\n\n\n\n<p>There is one <code>spc<\/code> file for each plugin.  We can review these files to see the default configuration, by default the files contain some of the available syntax, but for our simple example we are going to create our own files.  To start with we are going to create a very simple CSV file in the <code>\/data\/container\/steampipe\/sp\/config<\/code> directory, since that path already has a bind map to <code>\/home\/steampipe\/.steampipe\/config<\/code> inside of the container.  Our example CSV file will only contain two columns, one for a server_name and another for the owner.  The contents of this <code>server-owner.csv<\/code> file will look like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>server_name,owner\ncore-control-21,Brian Wuchner\ncore-vcenter01,Brian Wuchner\nbeet-farm-01,Dwight Schrute<\/code><\/pre>\n\n\n\n<p>To tell steampipe how to find the CSV file, we are going to create a new <code>csv.spc<\/code> file.  I did this by renaming the default <code>csv.spc<\/code> (with the syntax <code>mv csv.spc csv.spc.old<\/code>) and then created a new file (with <code>vi csv.spc<\/code>).  Our new file only contains the following information:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>connection \"csv\" {\n  plugin = \"csv\"\n  paths = &#91;\"\/home\/steampipe\/.steampipe\/config\/server-owner.csv\"]\n}<\/code><\/pre>\n\n\n\n<p>This is a very straightforward file &#8212; it shows that we are using the CSV plugin and specifically looking at the <code>server-owner.csv<\/code> file.  Lets investigate this CSV file to see how things work.  First up, we will enter the interactive query mode using <code>sp query<\/code> and then do a very basic select all statement against the server-owner file.  Then we will add a bit more, just to get the hang of SQL again by adding a where clause.  Finally, we will <code>.quit<\/code> the query editor.  The output of these commands can be seen below.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@lab-dock-14 &#91; \/data\/container\/steampipe\/sp\/config ]# sp query\nWelcome to Steampipe v0.18.5\nFor more information, type .help\n&gt; select * from \"server-owner\"\n+-----------------+----------------+---------------------------+\n| server_name     | owner          | _ctx                      |\n+-----------------+----------------+---------------------------+\n| beet-farm-01    | Dwight Schrute | {\"connection_name\":\"csv\"} |\n| core-control-21 | Brian Wuchner  | {\"connection_name\":\"csv\"} |\n| core-vcenter01  | Brian Wuchner  | {\"connection_name\":\"csv\"} |\n+-----------------+----------------+---------------------------+\n&gt; select server_name from \"server-owner\" where owner ilike '%dwight%'\n+--------------+\n| server_name  |\n+--------------+\n| beet-farm-01 |\n+--------------+\n&gt; .quit<\/code><\/pre>\n\n\n\n<p>Working with a CSV file is a basic example and we are only using it above to demonstrate how this would work.  The article promised we&#8217;d cover VMware vSphere, so we will do that next.<\/p>\n\n\n\n<p>To connect to vSphere we previously installed the <code>theapsgroup\/vsphere<\/code> plugin.  We now need to define a <code>spc<\/code> file that tells it where to find the vSphere environments, just like we did with the path to the CSV file before.  I start by backing up the default file (<code>mv vsphere.spc vsphere.spc.old<\/code>) and then creating a new file (<code>vi vsphere.spc<\/code>).  This new <code>vsphere.spc<\/code> file will have a few more required attributes than the <code>csv.spc<\/code> from earlier, as we need to pass in server name, username, password, etc.  Here is the sample <code>vsphere.spc<\/code> file from my lab.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>connection \"vsphere_vc1\" {\n  plugin = \"theapsgroup\/vsphere\"\n  vsphere_server  = \"vc1.example.com\"\n  user  = \"svc-vspherero@lab.enterpriseadmins.org\"\n  password  = \"Real-password-here!\"\n  allow_unverified_ssl = true\n}\n\nconnection \"vsphere_vc3\" {\n  plugin = \"theapsgroup\/vsphere\"\n  vsphere_server  = \"vc3.example.com\"\n  user  = \"administrator@vsphere.local\"\n  password  = \"VMware1!\"\n  allow_unverified_ssl = true\n}\n\nconnection \"vsphere_t106\" {\n  plugin = \"theapsgroup\/vsphere\"\n  vsphere_server  = \"t106-vcsa-01.lab.enterpriseadmins.org\"\n  user  = \"administrator@vsphere.local\"\n  password  = \"VMware1!\"\n  allow_unverified_ssl = true\n}\n\n\nconnection \"vmware_vsphere_all\" {\n  plugin = \"theapsgroup\/vsphere\"\n  type = \"aggregator\"\n  connections = &#91;\"vsphere_vc1\",\"vsphere_vc3\",\"vsphere_t106\"]\n}<\/code><\/pre>\n\n\n\n<p>As you can see, I have three different VMware vSphere environments listed, with plugin name, server name, and other details.  In addition, there is an aggregator connection that groups all of these environments together.  I could have multiple aggregations defined, such as one for prod and another for development instances.  Lets run a few test queries just like we did with the CSV example above.<\/p>\n\n\n\n<p>Once we enter the interactive query mode, we will see some autocompletion samples showing what tables are available for our vSphere data.  The common stuff like datastore, host, network, and VMs are present.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/02\/image-4.png\"><img loading=\"lazy\" decoding=\"async\" width=\"571\" height=\"152\" src=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/02\/image-4.png\" alt=\"\" class=\"wp-image-1782\" srcset=\"https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/02\/image-4.png 571w, https:\/\/enterpriseadmins.org\/blog\/wp-content\/uploads\/2023\/02\/image-4-300x80.png 300w\" sizes=\"auto, (max-width: 571px) 100vw, 571px\" \/><\/a><\/figure>\n\n\n\n<p>Lets try a couple of simple examples.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@lab-dock-14 &#91; \/data\/container\/steampipe\/sp\/config ]# sp query\nWelcome to Steampipe v0.18.5\nFor more information, type .help\n> select name, moref, product from vmware_vsphere_all.vsphere_host\n+---------------------------------------+------------+----------------------------------+\n| name                                  | moref      | product                          |\n+---------------------------------------+------------+----------------------------------+\n| euc-esx-22.lab.enterpriseadmins.org   | host-25601 | VMware ESXi 7.0.3 build-20328353 |\n| dr-esx-31.lab.enterpriseadmins.org    | host-25572 | VMware ESXi 7.0.3 build-20328353 |\n| core-esxi-33.lab.enterpriseadmins.org | host-34795 | VMware ESXi 7.0.3 build-21053776 |\n| core-esxi-34.lab.enterpriseadmins.org | host-34781 | VMware ESXi 7.0.3 build-21053776 |\n| euc-esx-21.lab.enterpriseadmins.org   | host-25598 | VMware ESXi 7.0.3 build-20328353 |\n| test-vesx-71.lab.enterpriseadmins.org | host-8     | VMware ESXi 8.0.0 build-21203435 |\n| test-vesx-72.lab.enterpriseadmins.org | host-12    | VMware ESXi 8.0.0 build-21203435 |\n| t106-vesx-03.lab.enterpriseadmins.org | host-105   | VMware ESXi 6.7.0 build-19195723 |\n| t106-vesx-01.lab.enterpriseadmins.org | host-303   | VMware ESXi 6.7.0 build-19195723 |\n| t106-vesx-02.lab.enterpriseadmins.org | host-106   | VMware ESXi 6.7.0 build-19195723 |\n+---------------------------------------+------------+----------------------------------+\n> select count(*) from vmware_vsphere_all.vsphere_vm\n+-------+\n| count |\n+-------+\n| 212   |\n+-------+\n> .quit<\/code><\/pre>\n\n\n\n<p>Ok, this was fun.  We can now query CSV files and vSphere data as if we were using a SQL database.  This is interesting, but what becomes really powerful is when we tie this together.  Since our data is in the same place\/format, we can do more complex SQL queries that join one or more data sources together.  In the next example, we will return a list of some VM details, along with the owner information from our CSV file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>> select vsphere_vm.name, vsphere_vm.power, vsphere_vm.memory, vsphere_vm.hardware, \"server-owner\".owner\r\nfrom vsphere_vm join \"server-owner\" on vsphere_vm.name = \"server-owner\".server_name\r\n+-----------------+------------+--------+----------+----------------+\r\n| name            | power      | memory | hardware | owner          |\r\n+-----------------+------------+--------+----------+----------------+\r\n| beet-farm-01    | poweredOff | 1024   | vmx-11   | Dwight Schrute |\r\n| core-control-21 | poweredOn  | 4096   | vmx-15   | Brian Wuchner  |\r\n| core-vcenter01  | poweredOn  | 16384  | vmx-10   | Brian Wuchner  |\r\n+-----------------+------------+--------+----------+----------------+<\/code><\/pre>\n\n\n\n<p>These are just some examples to get started.  If you check out the <a href=\"https:\/\/steampipe.io\/\">steampipe.io<\/a> site, you&#8217;ll find more examples and additional plugins covering other technologies, such as <code>net<\/code> that would allow you to query an SSL certificate (among many other things), <code>ldap<\/code> which can query LDAP\/Active Directory, and other plugins for many cloud providers like AWS and Azure. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>I was recently listening to an episode of the Unexplored Territory podcast (episode #023 &#8211; Introducing Oracle Cloud VMware Solution with Richard Garsthagen). At the end of each episode, the hosts ask the guest about a technology that should be &hellip; <a href=\"https:\/\/enterpriseadmins.org\/blog\/scripting\/getting-started-with-steampipe-io-to-query-vmware-vsphere\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":6,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[3,4],"tags":[],"class_list":["post-1774","post","type-post","status-publish","format-standard","hentry","category-scripting","category-virtualization"],"_links":{"self":[{"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/posts\/1774","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/comments?post=1774"}],"version-history":[{"count":4,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/posts\/1774\/revisions"}],"predecessor-version":[{"id":1783,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/posts\/1774\/revisions\/1783"}],"wp:attachment":[{"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/media?parent=1774"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/categories?post=1774"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/enterpriseadmins.org\/blog\/wp-json\/wp\/v2\/tags?post=1774"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}