Skip to content

Instantly share code, notes, and snippets.

@kwunlyou
Last active February 28, 2022 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kwunlyou/db4db9d0e9a643105db704d3815c5c7f to your computer and use it in GitHub Desktop.
Save kwunlyou/db4db9d0e9a643105db704d3815c5c7f to your computer and use it in GitHub Desktop.
# original version: https://raw.githubusercontent.com/aws-samples/amazon-sagemaker-notebook-instance-lifecycle-config-samples/master/scripts/auto-stop-idle/autostop.py
# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License").
# You may not use this file except in compliance with the License.
# A copy of the License is located at
#
# https://aws.amazon.com/apache-2-0/
#
# or in the "license" file accompanying this file. This file is distributed
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied. See the License for the specific language governing
# permissions and limitations under the License.
import requests
from datetime import datetime
import getopt, sys
import urllib3
import boto3
import json
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Usage
usageInfo = """Usage:
This scripts checks if a notebook is idle for X seconds if it does, it'll stop the notebook:
python autostop.py --time <time_in_seconds> [--port <jupyter_port>] [--ignore-connections]
Type "python autostop.py -h" for available options.
"""
# Help info
helpInfo = """-t, --time
Auto stop time in seconds
-p, --port
jupyter port
-c --ignore-connections
Stop notebook once idle, ignore connected users
-h, --help
Help information
"""
# Read in command-line parameters
idle = True
port = '8443'
ignore_connections = False
try:
opts, args = getopt.getopt(sys.argv[1:], "ht:p:c", ["help","time=","port=","ignore-connections"])
if len(opts) == 0:
raise getopt.GetoptError("No input parameters!")
for opt, arg in opts:
if opt in ("-h", "--help"):
print(helpInfo)
exit(0)
if opt in ("-t", "--time"):
time = int(arg)
if opt in ("-p", "--port"):
port = str(arg)
if opt in ("-c", "--ignore-connections"):
ignore_connections = True
except getopt.GetoptError:
print(usageInfo)
exit(1)
# Missing configuration notification
missingConfiguration = False
if not time:
print("Missing '-t' or '--time'")
missingConfiguration = True
if missingConfiguration:
exit(2)
def is_idle(last_activity):
last_activity = datetime.strptime(last_activity,"%Y-%m-%dT%H:%M:%S.%fz")
if (datetime.now() - last_activity).total_seconds() > time:
print('Notebook is idle. Last activity time = ', last_activity)
return True
else:
print('Notebook is not idle. Last activity time = ', last_activity)
return False
def get_notebook_name():
log_path = '/opt/ml/metadata/resource-metadata.json'
with open(log_path, 'r') as logs:
_logs = json.load(logs)
return _logs['ResourceName']
# This is hitting Jupyter's sessions API: https://github.com/jupyter/jupyter/wiki/Jupyter-Notebook-Server-API#Sessions-API
response = requests.get('https://localhost:'+port+'/api/sessions', verify=False)
data = response.json()
if len(data) > 0:
for notebook in data:
# Idleness is defined by Jupyter
# https://github.com/jupyter/notebook/issues/4634
if notebook['kernel']['execution_state'] == 'idle':
if not ignore_connections:
if notebook['kernel']['connections'] == 0:
if not is_idle(notebook['kernel']['last_activity']):
idle = False
else:
idle = False
else:
if not is_idle(notebook['kernel']['last_activity']):
idle = False
else:
print('Notebook is not idle:', notebook['kernel']['execution_state'])
idle = False
else:
client = boto3.client('sagemaker')
uptime = client.describe_notebook_instance(
NotebookInstanceName=get_notebook_name()
)['LastModifiedTime']
if not is_idle(uptime.strftime("%Y-%m-%dT%H:%M:%S.%fz")):
idle = False
# check code-server
if idle:
import re
import subprocess
import shlex
p = subprocess.run(shlex.split("pgrep -oaf code-server.*port"), capture_output=True)
if p.returncode == 0:
res = re.findall("port\s([-+]?\d+)", p.stdout.decode())
if res:
response = requests.get('http://localhost:'+res[0]+'/healthz', verify=False)
if response.json()["status"] == "alive":
idle = False
if idle:
print('Closing idle notebook')
client = boto3.client('sagemaker')
client.stop_notebook_instance(
NotebookInstanceName=get_notebook_name()
)
else:
print('Notebook not idle. Pass.')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment