For my VMworld 2016 breakout sessions this year, I wanted to demonstrate new functionality that was added to Auto Deploy. After exploring a few ideas, I settled on leveraging the new Script Bundle feature to send a post-boot tweet directly from stateless ESXi hosts. I figured sending a tweet would be an effective way to highlight the ability to integrate with arbitrary REST-based services. Interestingly, I ran into someone recently who was part of a DevOps team that used a private Twitter account for posting various alerts for the group to see – so it’s not as far-fetched as it seems!

Below is a Python script that can send a tweet directly from the console of a VMware ESXi 6.0 host. vCenter Server 6.5 with Auto Deploy supports multiple versions of ESXi, and I chose to use 6.0 here. Note that ESXi 6.5 includes Python 3, so this script would need some modification to work with that release. I got a head start on the functionality by taking some ideas from Chris Wood.

In order to authenticate with Twitter, it is first necessary to visit the Twitter App Management portal to generate a consumer key and access token. Plug them into the script accordingly.

The script accepts one argument: a string, wrapped in quotes, that will be posted to your Twitter timeline.

./tweet_from_esxi.py "Sent from an ESXi host"

The demo I ran at the INF8920 breakout session was slightly different because scripts cannot accept arguments in that case. Hopefully the recording will eventually be posted on the VMworld site, but the fate is unclear at the moment.

#!/usr/bin/env python # Send a tweet from ESXi 6.0 # Eric Gray -- Inspired by Chris Wood http://bit.ly/2fWjmmR import base64 import urllib, urllib2 import hashlib import random import time, os, sys if len(sys.argv) != 2: print "Pass this script a string (wrapped in quotes) to tweet." exit(1) # Twitter credentials consumer_key = "zLC6...ne" consumer_secret = "hcDZ...i9" access_token = "7833...Fq" token_secret = "G2c1...jmv" status = sys.argv[1] method = "POST" url = "https://api.twitter.com/1.1/statuses/update.json" parameters = { "oauth_consumer_key": consumer_key, "oauth_nonce": hashlib.sha1(str(random.random())).hexdigest(), "oauth_signature_method": "HMAC-SHA1", "oauth_timestamp": str(int(time.time())), "oauth_token": access_token, "oauth_version": "1.0", "status": status } # Build the string that forms the base of the signature base_string = "%s&%s&%s" % (method, urllib.quote(url, ""), urllib.quote('&'.join(sorted("%s=%s" % (key, value) for key, value in parameters.iteritems())), "")) # because ESXi does not have the hmac Python module... trans_5C = "".join([chr(x ^ 0x5C) for x in xrange(256)]) trans_36 = "".join([chr(x ^ 0x36) for x in xrange(256)]) outer = hashlib.sha1() inner = hashlib.sha1() KEY = "%s&%s" % (urllib.quote(consumer_secret, ""), urllib.quote(token_secret, "")) KEY = hashlib.sha1(KEY).digest() KEY = KEY + chr(0) * (inner.block_size - len(KEY)) outer.update(KEY.translate(trans_5C)) inner.update(KEY.translate(trans_36)) inner.update(base_string) outer.update(inner.digest()) parameters['oauth_signature'] = base64.b64encode(outer.digest().rstrip('

')) auth_header = 'OAuth %s' % ', '.join(sorted('%s="%s"' % (urllib.quote(key, ""), urllib.quote(value, "")) for key, value in parameters.iteritems() if key != 'status')) body = "status=%s" % status twitter_request = urllib2.Request(url, body) twitter_request.add_header("Authorization", auth_header) twitter_request.add_header('Content-Type', 'application/x-www-form-urlencoded') urllib2.urlopen(twitter_request) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 #!/usr/bin/env python # Send a tweet from ESXi 6.0 # Eric Gray -- Inspired by Chris Wood http://bit.ly/2fWjmmR import base64 import urllib , urllib2 import hashlib import random import time , os , sys if len ( sys . argv ) != 2 : print "Pass this script a string (wrapped in quotes) to tweet." exit ( 1 ) # Twitter credentials consumer_key = "zLC6...ne" consumer_secret = "hcDZ...i9" access_token = "7833...Fq" token_secret = "G2c1...jmv" status = sys . argv [ 1 ] method = "POST" url = "https://api.twitter.com/1.1/statuses/update.json" parameters = { "oauth_consumer_key" : consumer_key , "oauth_nonce" : hashlib . sha1 ( str ( random . random ( ) ) ) . hexdigest ( ) , "oauth_signature_method" : "HMAC-SHA1" , "oauth_timestamp" : str ( int ( time . time ( ) ) ) , "oauth_token" : access_token , "oauth_version" : "1.0" , "status" : status } # Build the string that forms the base of the signature base_string = "%s&%s&%s" % ( method , urllib . quote ( url , "" ) , urllib . quote ( '&' . join ( sorted ( "%s=%s" % ( key , value ) for key , value in parameters . iteritems ( ) ) ) , "" ) ) # because ESXi does not have the hmac Python module... trans_5C = "" . join ( [ chr ( x ^ 0x5C ) for x in xrange ( 256 ) ] ) trans_36 = "" . join ( [ chr ( x ^ 0x36 ) for x in xrange ( 256 ) ] ) outer = hashlib . sha1 ( ) inner = hashlib . sha1 ( ) KEY = "%s&%s" % ( urllib . quote ( consumer_secret , "" ) , urllib . quote ( token_secret , "" ) ) KEY = hashlib . sha1 ( KEY ) . digest ( ) KEY = KEY + chr ( 0 ) * ( inner . block_size - len ( KEY ) ) outer . update ( KEY . translate ( trans_5C ) ) inner . update ( KEY . translate ( trans_36 ) ) inner . update ( base_string ) outer . update ( inner . digest ( ) ) parameters [ 'oauth_signature' ] = base64 . b64encode ( outer . digest ( ) . rstrip ( '

' ) ) auth_header = 'OAuth %s' % ', ' . join ( sorted ( '%s="%s"' % ( urllib . quote ( key , "" ) , urllib . quote ( value , "" ) ) for key , value in parameters . iteritems ( ) if key != 'status' ) ) body = "status=%s" % status twitter_request = urllib2 . Request ( url , body ) twitter_request . add_header ( "Authorization" , auth_header ) twitter_request . add_header ( 'Content-Type' , 'application/x-www-form-urlencoded' ) urllib2 . urlopen ( twitter_request )

For more information on the Script Bundle feature, check out William Lam’s recent post on the topic.

(Visited 3,197 times, 1 visits today)