Skip to content

Instantly share code, notes, and snippets.

@why-not
Last active October 16, 2023 23:29
  • Star 14 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
Star You must be signed in to star a gist
Embed
What would you like to do?
Automatically Shutting Down and Deallocating an AZURE VM (when idle AND no one is logged in via SSH)
"""
The script is the easy part, installing it into the unfriendly(imo) cron system and
making all the permissions and paths are set correctly is another issue altogether.
cron will default to run as a root, so your scripts will fail because it is not running
in the correct python environment, also root might not have the paths for commands like 'python'
So best to run this in the user space where you are testing this script already.
Here is a cron command to add to the current user's cron than doing it for root.
sudo crontab -u ec2-user -e
Then add a line like this there. Notice how you have to activate the python project you are in.
Also notice I had to say the whole path to activate. Hopefully after this it should just work.
* * * * * source /usr/local/bin/activate pytorch && python /home/ec2-user/workspace/code/stop_idle_aws.py > /tmp/stop_status
Alternative method:
If you want to install the job into root's cron, then the following note can help.
# This is how the cron file should look like.
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/sn$
* * * * * /home/script/stop-idle-azure.py > /tmp/user_error.log
Watchout, for some reason cron files seem to require an extra new line at the end,
consult this SO: https://askubuntu.com/questions/23009/why-crontab-scripts-are-not-working
Also take care to setup a PATH variable for the cron explicitly. It doesn't see
your regular PATH variable.
"""
# ----
# Here is the code for stop-idle-azure.py
#!/usr/bin/env python
# make sure these commands run and do the proper thing.
# You might need to install azure cli:
# "sudo apt install azure-cli " in ubuntu.
# netstat -tnpa | grep 'ESTABLISHED.*sshd'
# az vm deallocate --name "myvmname" --resource-group "myvmresourcegroup"
import re
import subprocess
THRESH = 75.0
NAME = "EDIT THIS WITH PROPER VALUES"
RESOURCE_GROUP = "EDIT THIS WITH PROPER VALUES"
def get_logged_in():
shellout = subprocess.Popen(['sudo', 'netstat', '-tnpa'], stdout=subprocess.PIPE)
shellout2 = subprocess.Popen(['grep', 'ESTABLISHED.*sshd'], stdin=shellout.stdout, stdout=subprocess.PIPE)
outlist = list(shellout2.stdout)
return len(outlist) == 0
def get_cpu_percent():
f = open("/proc/loadavg", "r")
cpu_list = f.readline().split()
cpu_percent = float(cpu_list[1])
return cpu_percent
# If you want to check how long a machine
# has been running and stop based on that.
def uptime():
with open('/proc/uptime', 'r') as f:
uptime_seconds = float(f.readline().split()[0])
return uptime_seconds
def main():
# check to make sure there are no active
# ssh connections, meaning no humans
# are working on the machine,
# then go ahead and check
# the cpu usage in percent, if it falls
# below some threshold, send the command
# to shutdown the vm and deallocate it.
logged_in = get_logged_in()
cpu_percent = get_cpu_percent()
print ("cpu_percent: ", cpu_percent)
if logged_in:
if cpu_percent < THRESH:
print ("no one logged in, and vm is idle, stopping and deallocating.. ")
subprocess.run(['az', 'vm', 'deallocate', "--name", NAME, "--resource-group", RESOURCE_GROUP])
else:
print("no one logged in, but vm is busy. leaving it alone..")
else:
print ("someone is logged in, leaving the vm alone.. ")
if __name__ == '__main__':
main()
@why-not
Copy link
Author

why-not commented Oct 4, 2019

@sagu94271 you can run the script inside the target vm itself, deallocation is not a problem as that is the final command we are running. Infact this script assumes that it is running inside the machine that needs to be shutdown when idle.

@vengateshk
Copy link

Thanks for the Script.. Please let us know the changes or script for Windows Servers (Azure) to get de-allocated when no user is logged in for 30 mins etc.

@why-not
Copy link
Author

why-not commented Dec 12, 2019

@vengateshk You would simply modify the if condition to something that fits your needs. For eg. "if cpu_percent < THRESH: " can be changed to "if cpu_percent < THRESH && not logged_in():" and you run your cron job every hour, you can have the required effect of de-allocating when no one is logged in and the cpu is idle as well.

@christianll9
Copy link

import psutil is not needed

@why-not
Copy link
Author

why-not commented Jul 7, 2021

import psutil is not needed

fixed, thanks.

@chinniprakash
Copy link

chinniprakash commented Apr 13, 2023

Could you pls tell me how to modify this code to meet below requirement .
I have several windows azure vms . I need to make sure if no-one logins by remote desktop/any other way of login , I want to shutdown the in-active vms. ( Any way , I have your code for CPU, subprocesses ) etc

@why-not
Copy link
Author

why-not commented Oct 16, 2023

@chinniprakash The code solves for this scenario, kindly refer to the function get_logged_in() which is exactly what you want. (provided any of those logins are using ssh to connect. In case they don't you will have to mod this function)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment