mirror of
https://github.com/spiffcode/hostile-takeover.git
synced 2025-12-23 06:57:23 +00:00
220 lines
7.4 KiB
Python
Executable File
220 lines
7.4 KiB
Python
Executable File
#!/usr/bin/python2.7
|
|
|
|
import md5
|
|
import os
|
|
import urllib2
|
|
import json
|
|
import sys
|
|
import time
|
|
import config
|
|
|
|
DRAIN = True
|
|
TERMINATE = True
|
|
|
|
SHUTDOWN_MINUTES = 5
|
|
sendcommand_secret = config.get('SENDCOMMAND_SECRET')
|
|
leaderboard_address = config.get('LEADERBOARD_ADDRESS_AND_PORT')
|
|
sendcommand_url = 'http://%s/api/sendcommand' % leaderboard_address
|
|
serverinfo_url = 'http://%s/api/serverinfo' % leaderboard_address
|
|
project_name = config.get('PROJECT_NAME')
|
|
|
|
#SHUTDOWN_MINUTES = 5
|
|
#sendcommand_url = 'http://localhost:8080/api/sendcommand'
|
|
#serverinfo_url = 'http://localhost:8080/api/serverinfo'
|
|
|
|
def get_serverinfo():
|
|
opener = urllib2.build_opener(urllib2.HTTPHandler)
|
|
request = urllib2.Request(serverinfo_url)
|
|
request.get_method = lambda: 'GET'
|
|
try:
|
|
response = opener.open(request).read()
|
|
except urllib2.HTTPError, e:
|
|
print 'Error %d, %s' % (e.code, e.read())
|
|
return None
|
|
return json.loads(response)
|
|
|
|
def get_updated_info(info):
|
|
serverinfo = get_serverinfo()
|
|
for i in serverinfo['infos']:
|
|
if i['name'] == info['name'] and i['start_utc'] == info['start_utc']:
|
|
return i
|
|
return None
|
|
|
|
def which_servers(serverinfo):
|
|
if len(serverinfo['infos']) == 0:
|
|
return None
|
|
index = 0
|
|
for info in serverinfo['infos']:
|
|
print 'Server #%d. Name: %s' % (index, info['name'])
|
|
for key in sorted(info.keys()):
|
|
if key == 'name':
|
|
continue
|
|
print ' %s: %s' % (key, info[key])
|
|
index = index + 1
|
|
|
|
info = None
|
|
while True:
|
|
try:
|
|
ans = raw_input('Which server number to drain and delete? ')
|
|
index = int(ans)
|
|
if index >= 0 and index < len(serverinfo['infos']):
|
|
info = serverinfo['infos'][index]
|
|
break
|
|
print 'Incorrect server number. Try again.'
|
|
except ValueError:
|
|
print 'Not a number. Try again.'
|
|
|
|
join_info = None
|
|
while True:
|
|
try:
|
|
ans = raw_input('Which server number should players join (-1 for none)? ')
|
|
index = int(ans)
|
|
if index >= 0 and index < len(serverinfo['infos']):
|
|
join_info = serverinfo['infos'][index]
|
|
break
|
|
if index == -1:
|
|
join_info = None
|
|
break
|
|
print 'Incorrect server number. Try again.'
|
|
except ValueError:
|
|
print 'Not a number. Try again.'
|
|
|
|
return info, join_info
|
|
|
|
def ask_continue(server_name, join_server, shutdown_count, player_count):
|
|
print 'PLEASE VERIFY:'
|
|
print '1. You wish to drain and delete server %s.' % server_name
|
|
print '2. You wish to start this process once the player count reaches <= %d.' % player_count
|
|
if join_server:
|
|
print '3. Once reached, remaining players will receive a message to join server %s.' % join_server
|
|
else:
|
|
print '3. Once reached, remaining players will receive a warning message every minute.'
|
|
print '4. The server will be deleted when the user count goes to zero or after %d minutes.' % shutdown_count
|
|
|
|
while True:
|
|
yesno = raw_input('Would you like to continue? (y/n) ')
|
|
if len(yesno) < 1:
|
|
continue
|
|
if yesno[0] == 'n' or yesno[0] == 'N':
|
|
return False
|
|
if yesno[0] == 'y' or yesno[0] == 'Y':
|
|
return True
|
|
|
|
def ask_player_count(server_name, info):
|
|
print '%s currently has a player count of %d.' % (server_name, info['player_count'])
|
|
while True:
|
|
s = raw_input('What player count should trigger the drain-delete process? ')
|
|
try:
|
|
return int(s)
|
|
except ValueError:
|
|
print '%s is not a number. Try again.' % s
|
|
|
|
def wait_player_count(server_name, info, player_count):
|
|
while True:
|
|
print '%s current player count: %d. Trigger: %d' % \
|
|
(server_name, info['player_count'], player_count)
|
|
if info['player_count'] <= player_count:
|
|
return
|
|
time.sleep(60)
|
|
info = get_updated_info(info)
|
|
|
|
def send_command(o):
|
|
j = json.dumps(o)
|
|
m = md5.new(j + sendcommand_secret)
|
|
body = m.hexdigest() + j
|
|
opener = urllib2.build_opener(urllib2.HTTPHandler)
|
|
request = urllib2.Request(sendcommand_url, data=body)
|
|
request.add_header('Content-Type', 'binary/octet-stream')
|
|
request.add_header('Content-Length', len(body))
|
|
request.get_method = lambda: 'POST'
|
|
try:
|
|
response = opener.open(request).read()
|
|
return True
|
|
except urllib2.HTTPError, e:
|
|
print 'error %d, %s' % (e.code, e.read())
|
|
return False
|
|
|
|
def drain_wait(info):
|
|
o = dict(info=dict(name=info['name'], start_utc=info['start_utc']),
|
|
command=dict(command='drain'))
|
|
print 'Sending drain command.'
|
|
if not send_command(o):
|
|
return False
|
|
while True:
|
|
print 'Waiting for drain confirmation.'
|
|
new_info = get_updated_info(info)
|
|
if not new_info:
|
|
return False
|
|
if new_info['status'] == 'drain':
|
|
print 'Drain confirmed.'
|
|
return True
|
|
time.sleep(30)
|
|
|
|
def send_shutdown_message(info, join_server, shutdown_count):
|
|
if join_server:
|
|
message = 'Shutdown in %d minutes. Join server %s now!' % \
|
|
(shutdown_count, join_server)
|
|
else:
|
|
message = 'Shutdown in %d minutes.' % shutdown_count
|
|
o = dict(info=dict(name=info['name'], start_utc=info['start_utc']),
|
|
command=dict(command='chat', name='Admin', message=message))
|
|
print 'Sending: %s: %s' % (o['command']['name'],
|
|
o['command']['message'])
|
|
return send_command(o)
|
|
|
|
def main():
|
|
print "NOTE: Before continuing ensure these steps have been taken:"
|
|
print "1. Install gcloud from here if not already installed:"
|
|
print " https://cloud.google.com/sdk/"
|
|
print "2. If already installed ensure it is up to date:"
|
|
print " $ gcloud components update"
|
|
print "3. Authenicate:"
|
|
print " $ gcloud auth login"
|
|
print "4. Select the proper project:"
|
|
print " $ gcloud config set project %s" % project_name
|
|
|
|
serverinfo = get_serverinfo()
|
|
if not serverinfo:
|
|
print 'could not get serverinfo.'
|
|
sys.exit(1)
|
|
|
|
info, join_info = which_servers(serverinfo)
|
|
if not info:
|
|
print 'no server selected.'
|
|
sys.exit(1)
|
|
server_name = '%s (start_utc: %s)' % (info['name'], info['start_utc'])
|
|
join_server = join_info['name'] if join_info else None
|
|
|
|
player_count = ask_player_count(server_name, info)
|
|
shutdown_count = SHUTDOWN_MINUTES
|
|
if not ask_continue(server_name, join_server, shutdown_count, player_count):
|
|
print 'no action taken.'
|
|
sys.exit(1)
|
|
|
|
wait_player_count(server_name, info, player_count)
|
|
|
|
if DRAIN:
|
|
print 'Setting %s to drain mode. Waiting for confirmation.' % server_name
|
|
if not drain_wait(info):
|
|
print 'could not set %s into drain mode. no action taken.' % server_name
|
|
sys.exit(1)
|
|
|
|
while shutdown_count != -1:
|
|
new_info = get_updated_info(info)
|
|
print 'players: %d' % new_info['player_count']
|
|
if new_info['player_count'] == 0:
|
|
break
|
|
send_shutdown_message(info, join_server, shutdown_count)
|
|
shutdown_count = shutdown_count - 1
|
|
time.sleep(60)
|
|
|
|
print 'deleting: %s instance name: %s' % (server_name, info['instance_name'])
|
|
|
|
if TERMINATE:
|
|
sys.exit(os.system('gcloud compute instances delete "%s" --quiet --zone us-central1-a' % (info['instance_name'])))
|
|
|
|
sys.exit(0)
|
|
|
|
if __name__ == '__main__':
|
|
main()
|