Using SaltStack Config api for Automation from vRA Catalog or cmd
A personal goal of mine for 2022 was to start doing more with Python when working with VMware SaltStack Config. As a Windows Admin most of my automation was done with PowerShell. All the examples you see in the salt documentation are written in Python, so to use Python for some processes makes sense.
I had a use case that made sense to use Python. I want to schedule reboots of AWS EC2 instances using SaltStack Config. For Servers that are on-prem I would always automate the process to create a server reboot scheduled task in vCenter. With AWS I want to use VMware SaltStack Config to schedule the Server Reboot.
Manual Steps:
Create a SaltStack Config Job to do the reboot.
I create a job named “vRA | Server Reboot”. This job will be used for all scheduled server reboots.
Copy the Python Code below and create a ScheduleServerReboot.py file that will be copied to the SSC server.
The Python Code completes the following steps:
Creates a Target that uses the grain “id” and will only target the Server that you want to reboot.
Creates a Run Once Schedule to use the job and new target that was created.
Sends an email to show that the run once schedule to reboot server was created.
SaltStack Config Server:
My SaltStack Config Server (SSC) is what VMware provides when using Life Cycle Manager (LCM) running Photon OS.
# --- Python Code ---# --- In my code I show the Password. In Production DO NOT DO THIS.# --- There are so many different ways to include encrypted PWs in the code. # --- Use what works best in your environment.# example to run the script# python3 /scripts/ScheduleServerReboot.py -name '2019DC' -dateTime '2022-06-25T23:00'importargparseimportpprintimportjsonfromdatetimeimportdatetimefromdatetimeimporttimedeltaimportrandomimportsmtplib,sslfromemail.mime.textimportMIMETextfromemail.mime.multipartimportMIMEMultipart# --- Generate a random ID numberrandomNumber=random.randint(0,1000)randomNumber='0000'+str(randomNumber)randomNumber=randomNumber[-4:]print('ID:',randomNumber)# --- parse argumentsparser=argparse.ArgumentParser(description="Create Targets",formatter_class=argparse.ArgumentDefaultsHelpFormatter)parser.add_argument("-name",help="Target Name")parser.add_argument("-dateTime",help="Schedule Date | Time")args=vars(parser.parse_args())# --- Set up variablesargName=args["name"]argDateTime=args["dateTime"]argDate=argDateTime[0:10]# --- Print the variablesprint('Server Name: ',argName)print('Date | Time: ',argDateTime)# --- Connect to SSC Serverhost='https://192.168.86.110'user='root'password='HackMe!'fromsseapiclient.tornadoimportSyncClientclient=SyncClient.connect(host,user,password,ssl_validate_cert=False)# --- Check to make sure minion existsminionName=''minionReturn=client.api.minions.get_minion_presence(minion_id=argName)#print(targetReturn)forxinminionReturn.ret['results']:#print(x)minionName=x['minion']print('minionName:',minionName)ifminionName=='':print('Minion not found!')minionExists='false'else:print('Minion found!')minionExists='true'# --- Create Target ID | NametargetID='id:'+argNametargetName="vRA | Reboot | "+argName+' | '+argDate+' | ID:'+randomNumberprint('Target ID:',targetID)print('Target Name:',targetName)# --- Create New SSC Targetclient.api.tgt.save_target_group(tgt={'*':{'tgt_type':'grain','tgt':targetID}},name=targetName)# --- Get UUID of new Target CreatedtargetReturn=client.api.tgt.get_target_group(name=targetName)forxintargetReturn.ret['results']:#print(x)targetUUID=x['uuid']print('Target UUID:',targetUUID)# --- Get UUID of Job to run in Schedule#jobReturn=client.api.job.get_jobs()jobName='vRA | Server Reboot'print('Job Name: ',jobName)jobReturn=client.api.job.get_jobs(name=jobName)forxinjobReturn.ret['results']:#print(x)jobUUID=x['uuid']print('Job UUID:',jobUUID)# -- Create a run once Schedule# 2022-06-21T13:21 - Date|Time format from vRAprint('Schedule Time:',argDateTime)# --- Create Schedule NamescheduleName='vRA | Reboot | '+argName+' | '+argDate+' | ID:'+randomNumberprint('Schedule Name:',scheduleName)# --- Create Run Once SchedulescheduleReturn=client.api.schedule.save(name=scheduleName,schedule={'once':argDateTime,'timezone':'America/New_York'},cmd="local",tgt_uuid=targetUUID,job_uuid=jobUUID)# --- Send Email about vRA Request using gmail.sender_email="dale.hassinger@gmail.com"receiver_email="dale.hassinger@vcrocs.info"password="HackMe!"message=MIMEMultipart("alternative")message["Subject"]="vRA Scheduled EC2 Reboot | "+argNamemessage["From"]=sender_emailmessage["To"]=receiver_email# --- Create HTML BodyifminionExists=='true':html="""
<html>
<body>
<div style="font-family: Arial, sans-serif; font-size: 14px;"><b>A Request to reboot a AWS EC2 was run from vRA.</b></div>
<div style="font-family: Arial, sans-serif; font-size: 14px;"></div><br>
<div style="font-family: Arial, sans-serif; font-size: 14px;"><b>EC2 Information:</b></div>
<ul style="list-style-type:disc">
<div style="font-family: Arial, sans-serif; font-size: 12px;"><li><b>EC2 Name: """+argName+"""</b></li></div>
<div style="font-family: Arial, sans-serif; font-size: 12px;"><li>Target Created: """+targetName+"""</li></div>
<div style="font-family: Arial, sans-serif; font-size: 12px;"><li>Schedule Created: """+scheduleName+"""</li></div>
<div style="font-family: Arial, sans-serif; font-size: 12px;"><li>Reboot Date | Time: """+argDateTime+"""</li></div>
</ul>
<div style="font-family: Arial, sans-serif; font-size: 11px;"><b>vCROCS - Automated IT </b></div>
<div style="font-family: Arial, sans-serif; font-size: 10px;">#VMware #vRealize #SaltStackConfig</div>
</body>
</html>
"""elifminionExists=='false':html="""
<html>
<body>
<div style="font-family: Arial, sans-serif; font-size: 14px;"><b>A Request to reboot a AWS EC2 was run from vRA.</b></div>
<div style="font-family: Arial, sans-serif; font-size: 14px;"></div><br>
<div style="font-family: Arial, sans-serif; font-size: 14px;"><b>EC2 Information:</b></div>
<ul style="list-style-type:disc">
<div style="font-family: Arial, sans-serif; font-size: 12px;"><li><b>EC2 Name: """+argName+"""</b></li></div>
</ul>
<div style="font-family: Arial, sans-serif; font-size: 14px;"><b>The Server Name was not found in Salt! Please double check name and try again!</b></div>
<div style="font-family: Arial, sans-serif; font-size: 14px;"></div><br>
<div style="font-family: Arial, sans-serif; font-size: 11px;"><b>vCROCS - Automated IT </b></div>
<div style="font-family: Arial, sans-serif; font-size: 10px;">#VMware #vRealize #SaltStackConfig</div>
</body>
</html>
"""# --- HTML MIMEText objectsemailHTML=MIMEText(html,"html")# --- Add the HTML part to MIMEMultipart messagemessage.attach(emailHTML)# --- Create secure connection and send HTML emailcontext=ssl.create_default_context()withsmtplib.SMTP_SSL("smtp.gmail.com",465,context=context)asserver:server.login(sender_email,password)server.sendmail(sender_email,receiver_email,message.as_string())
Example of email that is sent when process completes.
Screen Shots of the SaltStack Config Job, Target and Schedule:
SSC Job:
SSC Target:
To run this process to reboot an AWS EC2 from the vRA catalog for Day 2 operations I used the OOTB (Out of The Box) orchestrator workflow named “Run SSH command”. I never modify the OOTB workflows. I cloned this Workflow and named it “Schedule EC2 Reboot”.
Original OOTB Workflow from vRO:
Cloned Worked in vRO:
Very simple form to fill out. Enter EC2 name and Date|Time.
The Workflow takes the data from the vRA custom form and does an SSH Connection to the SSC server and runs a single line command using the data from the form as arguments:
When I write about vRealize Automation ("vRA") I always say there are many ways to accomplish the same task. SaltStack Config is the same way. I am showing what I felt was important to see but every organization/environment will be different. There is no right or wrong way to use Salt. This is a GREAT Tool that is included with your vRealize Suite Advanced/Enterprise license. If you own the vRealize Suite, you own SaltStack Config.
If you like wearing Crocs and want to get a pair like I wear, follow this link to Amazon:
My Favorite Crocs
If you found this Blog article useful and it helped you, Buy me a coffee to start my day.