{"id":3678,"date":"2018-11-15T16:32:52","date_gmt":"2018-11-15T22:32:52","guid":{"rendered":"http:\/\/benincosa.com\/?p=3678"},"modified":"2018-11-15T16:36:19","modified_gmt":"2018-11-15T22:36:19","slug":"esxi-kickstart-and-automated-vcenter-registration","status":"publish","type":"post","link":"https:\/\/benincosa.com\/?p=3678","title":{"rendered":"ESXi Kickstart and automated vCenter registration"},"content":{"rendered":"<p>I haven&#8217;t worked on VMware for a while but needed to work on a project to automatically install ESXi on a few servers.\u00a0 I invented a tool called KUBAM that was originally for deploying Kubernetes on UCS Bare Metal (KUBAM) but have realized there are a lot of people that can benefit from the use of vMedia policy installations.\u00a0 I&#8217;ve written a few articles on this method <a href=\"https:\/\/blogs.cisco.com\/developer\/kubam-let-your-data-center-dance\">here<\/a> and <a href=\"https:\/\/kubam.io\/\">there.<\/a><\/p>\n<p>When looking to deploy ESXi we had made the kickstart portion work perfectly and even upgraded it to 6.7.\u00a0 However, when looking for information on how to automatically register the ESXi servers to vCenter after the installation was concluded the best we found was information from the legendary WIlliam Lam at VMware from <a href=\"https:\/\/www.virtuallyghetto.com\/2011\/03\/how-to-automatically-add-esxi-host-to.html\">a post in 2011<\/a>.\u00a0 Here we are 7 almost 8 years later still trying to accomplish the same thing.\u00a0 The problem is the post was written in 2011 and ESXi updated the version from Python 2 to Python 3 and so parts of the script don&#8217;t work.\u00a0 I&#8217;ve updated it in a dirty way to make it work and checked the code into the KUBAM project.\u00a0 It could use some cleaning up to make it nice like William&#8217;s python.\u00a0 I may do that as time goes on.\u00a0 For now here is the code:<\/p>\n<pre class=\"lang:python decode:true \">import sys,re,os,urllib,base64,syslog,socket\r\nimport urllib.request as request\r\nimport ssl\r\n\r\n# used for unverified SSL\/TLS certs. Insecure, not good for public.\r\nssl._create_default_https_context = ssl._create_unverified_context\r\n\r\n## Variables that need to be filled out for different environments ##\r\n# URL of vcenter, just the IP address\r\nvcenter = \"10.93.140.100\"\r\n\r\n# Data center\r\n#cluster = \"&lt;datacenter&gt;\/host\/&lt;cluster&gt;\"\r\ncluster = \"Lucky Lab (LK02)\/host\/SandyBridge\"\r\n\r\n# vCenter credentials\r\nuser = \"administrator@vsphere.local\"\r\npassword = \"Cisco.123\"\r\n\r\n# host ESXi credentials\r\nhost_username = \"root\"\r\nhost_password = \"Cisco.123\"\r\n\r\nurl = \"https:\/\/\" + vcenter + \"\/mob\/?moid=SearchIndex&amp;method=findByInventoryPath\"\r\n\r\n\r\npassman = request.HTTPPasswordMgrWithDefaultRealm()\r\npassman.add_password(None,url, user, password)\r\nauthhandler = request.HTTPBasicAuthHandler(passman)\r\nopener = request.build_opener(authhandler)\r\nrequest.install_opener(opener)\r\n#cont = ssl._create_unverified_context()\r\n#ssl._create_default_https_context = ssl._create_unverified_context()\r\nreq = request.Request(url)\r\n#cont = ssl._create_unverified_context()\r\n#page = request.urlopen(req, context=context)\r\npage = request.urlopen(req)\r\npage_content = page.read().decode('utf-8')\r\n#print(page_content)\r\n\r\nreg = re.compile('name=\"vmware-session-nonce\" type=\"hidden\" value=\"?([^\\s^\"]+)\"')\r\nnonce = reg.search(page_content).group(1)\r\n\r\nheaders = page.info()\r\ncookie = headers.get(\"Set-Cookie\")\r\n\r\nparams = {'vmware-session-nonce':nonce,'inventoryPath':cluster}\r\ne_params = urllib.parse.urlencode(params)\r\n#print(e_params)\r\nbin_data = e_params.encode('utf8')\r\nreq = request.Request(url, bin_data, headers={\"Cookie\":cookie})\r\npage = request.urlopen(req)\r\npage_content = page.read().decode('utf-8')\r\n#print(page_content)\r\n\r\nclusterMoRef = re.search('domain-c[0-9]*',page_content)\r\nif clusterMoRef:\r\n\tprint(\"Found cluster: \" + cluster)\r\nelse:\r\n\topener.close()\r\n\tsys.exit(1)\r\n\r\n# cert stuff\r\ncmd = \"openssl x509 -sha1 -in \/etc\/vmware\/ssl\/rui.crt -noout -fingerprint\"\r\ntmp = os.popen(cmd)\r\ntmp_sha1 = tmp.readline()\r\ntmp.close()\r\ns1 = re.split('=',tmp_sha1)\r\ns2 = s1[1]\r\ns3 = re.split('\\n', s2)\r\nsha1 = s3[0]\r\n\r\nif sha1:\r\n\tprint(\"Hash: \", sha1)\r\nelse:\r\n\topener.close()\r\n\tsys.exit(1)\r\n\r\nxml = '&lt;spec xsi:type=\"HostConnectSpec\"&gt;&lt;hostName&gt;%hostname&lt;\/hostName&gt;&lt;sslThumbprint&gt;%sha&lt;\/sslThumbprint&gt;&lt;userName&gt;%user&lt;\/userName&gt;&lt;password&gt;%pass&lt;\/password&gt;&lt;force&gt;1&lt;\/force&gt;&lt;\/spec&gt;'\r\n \r\n# Code to extract IP Address to perform DNS lookup to add FQDN to vCenter\r\nhostip = socket.gethostbyname(socket.gethostname())\r\n\r\nif hostip:\r\n\tprint(\"IP address of host: \", hostip.strip())\r\nelse:\r\n\topener.close()\r\n\tsys.exit(1)\r\n\r\n# could add logic to do DNS lookup, but no dns in our environment. \r\n\r\nxml = xml.replace(\"%hostname\",hostip)\r\nxml = xml.replace(\"%sha\",sha1)\r\nxml = xml.replace(\"%user\",host_username)\r\nxml = xml.replace(\"%pass\",host_password)\r\nprint(xml)\r\n# now join to vcenter cluster\r\ntry: \r\n\turl = \"https:\/\/\" + vcenter + \"\/mob\/?moid=\" + clusterMoRef.group() + \"&amp;method=addHost\"\r\n\tparams = {'vmware-session-nonce':nonce,'spec':xml,'asConnected':'1','resourcePool':'','license':''}\r\n\te_params = urllib.parse.urlencode(params)\r\n\tbin_data = e_params.encode('utf8')\r\n\treq = request.Request(url, bin_data, headers={\"Cookie\":cookie})\r\n\tpage = request.urlopen(req).read()\r\nexcept IOError as e:\r\n\topener.close()\r\n\tprint(\"Couldn't join cluster\", e)\r\n\tsys.exit(1)\r\nelse:\r\n\tprint(\"Joined vcenter cluster!\")\r\n\turl = \"https:\/\/\" + vcenter + \"\/mob\/?moid=SessionManager&amp;method=logout\"\r\n\tparams = {'vmware-session-nonce':nonce}\r\n\te_params = urllib.parse.urlencode(params)\r\n\tbin_data = e_params.encode('utf8')\r\n\treq = request.Request(url, bin_data, headers={\"Cookie\":cookie})\r\n\tpage = request.urlopen(req).read()\r\n\tsys.exit(0)\r\n<\/pre>\n<p>A few notes here:<\/p>\n<ul>\n<li>urllib2 was split into different urllib packages so that is no longer included<\/li>\n<li>The top line sets the default context to not do cert checks.\u00a0 Usually I find in enterprise companies there are no certs so people just accept the cert even though there is no root authority.<\/li>\n<li>I only have IP addresses for hostnames, but if you have DNS then you will probably want to add contents from William&#8217;s <a href=\"https:\/\/github.com\/lamw\/vghetto-scripts\/blob\/master\/python\/joinvCenter.py\">script.<\/a><\/li>\n<li>I&#8217;m pretty lazy with this and not updating the logs.\u00a0 I&#8217;ll probably go back and spend some time doing that in the future if I need to.<\/li>\n<\/ul>\n<p>The code is found in the <a href=\"https:\/\/github.com\/CiscoUcs\/KUBaM\/blob\/master\/kubam\/templates\/register-with-vcenter.py\">KUBAM project here<\/a>.<\/p>\n<p>To use this code, you can include it in your ESXi Kickstart file.\u00a0 <a href=\"https:\/\/github.com\/CiscoUcs\/KUBaM\/blob\/master\/kubam\/templates\/esxi6.5-registervmware.tmpl\">An example in the same directory is here.<\/a>\u00a0 Notice the key are the last lines:<\/p>\n<pre class=\"lang:sh decode:true \"># register with vcenter\r\nesxcli network firewall ruleset set -e true -r httpClient\r\nwget -O vcenter.py http:\/\/10.93.140.118\/kubam\/vcenter.py \r\n\/bin\/python vcenter.py<\/pre>\n<p>We put the script (renamed vcenter.py) in the ~\/kubam directory of the installer.\u00a0 Then as the machine boots up it grabs the file and runs the script registering itself.<\/p>\n<p>The install is nice and without glamour.\u00a0 It simply adds a new server to the cluster:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-medium wp-image-3681\" src=\"http:\/\/benincosa.com\/wp-content\/uploads\/2018\/11\/Screen-Shot-2018-11-15-at-2.34.48-PM-300x43.png\" alt=\"\" width=\"300\" height=\"43\" srcset=\"https:\/\/benincosa.com\/wp-content\/uploads\/2018\/11\/Screen-Shot-2018-11-15-at-2.34.48-PM-300x43.png 300w, https:\/\/benincosa.com\/wp-content\/uploads\/2018\/11\/Screen-Shot-2018-11-15-at-2.34.48-PM.png 715w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>With my example I didn&#8217;t add another user account but I recommend it.\u00a0 I also didn&#8217;t base encode the passwords but that is something you could do as well.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I haven&#8217;t worked on VMware for a while but needed to work on a project to automatically install ESXi on a few servers.\u00a0 I invented a tool called KUBAM that was originally for deploying Kubernetes on UCS Bare Metal (KUBAM) but have realized there are a lot of people that can benefit from the use&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[873,101,39],"tags":[877,878,874,876,875,13,879,981],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts\/3678"}],"collection":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3678"}],"version-history":[{"count":3,"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts\/3678\/revisions"}],"predecessor-version":[{"id":3682,"href":"https:\/\/benincosa.com\/index.php?rest_route=\/wp\/v2\/posts\/3678\/revisions\/3682"}],"wp:attachment":[{"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3678"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3678"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/benincosa.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3678"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}