| Server IP : 172.67.216.113 / Your IP : 172.71.28.146 [ Web Server : Apache System : Linux cpanel01wh.bkk1.cloud.z.com 2.6.32-954.3.5.lve1.4.59.el6.x86_64 #1 SMP Thu Dec 6 05:11:00 EST 2018 x86_64 User : cp648411 ( 1354) PHP Version : 7.2.34 Disable Function : NONE Domains : 0 Domains MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /proc/self/root/usr/lib/python2.6/site-packages/supervisor/ |
Upload File : |
import os
import re
import cgi
import meld3
import time
import traceback
import urllib
from options import readFile
from medusa import default_handler
from medusa import producers
from medusa.http_server import http_date
from medusa.http_server import get_header
from medusa import producers
from supervisord import ProcessStates
from http import NOT_DONE_YET
import xmlrpc
class DeferredWebProducer:
""" A medusa producer that implements a deferred callback; requires
a subclass of asynchat.async_chat that handles NOT_DONE_YET sentinel """
CONNECTION = re.compile ('Connection: (.*)', re.IGNORECASE)
def __init__(self, request, callback):
self.callback = callback
self.request = request
self.finished = False
self.delay = float(callback.delay)
def more(self):
if self.finished:
return ''
try:
response = self.callback()
if response is NOT_DONE_YET:
return NOT_DONE_YET
self.finished = True
return self.sendresponse(response)
except:
# report unexpected exception back to server
traceback.print_exc()
self.finished = True
self.request.error(500)
def sendresponse(self, response):
headers = response.get('headers', [])
for header in headers:
self.request[header] = headers[header]
if headers.get('Location'):
self.request['Content-Type'] = 'text/html'
self.request['Content-Length'] = 0
self.request.error(301)
return
body = response.get('body', '')
content_type = response.get('content_type', 'text/html')
self.request['Content-Type'] = content_type
self.request['Content-Length'] = len(body)
self.request.push(body)
connection = get_header(self.CONNECTION, self.request.header)
close_it = 0
wrap_in_chunking = 0
if self.request.version == '1.0':
if connection == 'keep-alive':
if not self.request.has_key('Content-Length'):
close_it = 1
else:
self.request['Connection'] = 'Keep-Alive'
else:
close_it = 1
elif self.request.version == '1.1':
if connection == 'close':
close_it = 1
elif not self.request.has_key ('Content-Length'):
if self.request.has_key ('Transfer-Encoding'):
if not self.request['Transfer-Encoding'] == 'chunked':
close_it = 1
elif self.request.use_chunked:
self.request['Transfer-Encoding'] = 'chunked'
wrap_in_chunking = 1
else:
close_it = 1
elif self.request.version is None:
close_it = 1
outgoing_header = producers.simple_producer (
self.request.build_reply_header())
if close_it:
self.request['Connection'] = 'close'
if wrap_in_chunking:
outgoing_producer = producers.chunked_producer (
producers.composite_producer (self.request.outgoing)
)
# prepend the header
outgoing_producer = producers.composite_producer(
[outgoing_header, outgoing_producer]
)
else:
# prepend the header
self.request.outgoing.insert(0, outgoing_header)
outgoing_producer = producers.composite_producer (
self.request.outgoing)
# apply a few final transformations to the output
self.request.channel.push_with_producer (
# globbing gives us large packets
producers.globbing_producer (
# hooking lets us log the number of bytes sent
producers.hooked_producer (
outgoing_producer,
self.request.log
)
)
)
self.request.channel.current_request = None
if close_it:
self.request.channel.close_when_done()
class ViewContext:
def __init__(self, **kw):
self.__dict__.update(kw)
class MeldView:
content_type = 'text/html'
delay = .5
def __init__(self, context):
self.context = context
template = self.context.template
if not os.path.isabs(template):
here = os.path.abspath(os.path.dirname(__file__))
template = os.path.join(here, template)
self.root = meld3.parse_xml(template)
self.callback = None
def __call__(self):
body = self.render()
if body is NOT_DONE_YET:
return NOT_DONE_YET
response = self.context.response
headers = response['headers']
headers['Content-Type'] = self.content_type
headers['Pragma'] = 'no-cache'
headers['Cache-Control'] = 'no-cache'
headers['Expires'] = http_date.build_http_date(0)
response['body'] = body
return response
def clone(self):
return self.root.clone()
class TailView(MeldView):
def render(self):
supervisord = self.context.supervisord
request = self.context.request
path, params, query, fragment = request.split_uri()
if not query:
tail = 'No process name found'
processname = None
else:
while query.startswith('?'):
query = query[1:]
params = cgi.parse_qs(query)
processname = params.get('processname',[None])[0]
if not processname:
tail = 'No process name found'
else:
rpcinterface = xmlrpc.SupervisorNamespaceRPCInterface(
supervisord)
try:
tail = rpcinterface.readProcessLog(processname, -1024, 0)
except xmlrpc.RPCError, e:
if e.code == xmlrpc.Faults.NO_FILE:
tail = 'No file for %s' % processname
else:
raise
root = self.clone()
title = root.findmeld('title')
title.content('Supervisor tail of process %s' % processname)
tailbody = root.findmeld('tailbody')
tailbody.content(tail)
refresh_anchor = root.findmeld('refresh_anchor')
if processname is not None:
refresh_anchor.attributes(href='tail.html?processname=%s' %
processname)
else:
refresh_anchor.deparent()
return root.write_xhtmlstring()
class StatusView(MeldView):
def actions_for_process(self, process):
state = process.get_state()
processname = process.config.name
start = {
'name':'Start',
'href':'index.html?processname=%s&action=start' % processname,
'target':None,
}
restart = {
'name':'Restart',
'href':'index.html?processname=%s&action=restart' % processname,
'target':None,
}
stop = {
'name':'Stop',
'href':'index.html?processname=%s&action=stop' % processname,
'target':None,
}
clearlog = {
'name':'Clear Log',
'href':'index.html?processname=%s&action=clearlog' % processname,
'target':None,
}
tailf = {
'name':'Tail -f',
'href':'logtail/%s' % processname,
'target':'_blank'
}
if state == ProcessStates.RUNNING:
actions = [restart, stop, clearlog, tailf]
elif state in (ProcessStates.STOPPED, ProcessStates.EXITED,
ProcessStates.FATAL):
actions = [start, None, clearlog, tailf]
else:
actions = [None, None, clearlog, tailf]
return actions
def css_class_for_state(self, state):
if state == ProcessStates.RUNNING:
return 'statusrunning'
elif state in (ProcessStates.FATAL, ProcessStates.BACKOFF):
return 'statuserror'
else:
return 'statusnominal'
def make_callback(self, processname, action):
message = None
supervisord = self.context.supervisord
# the rpc interface code is already written to deal properly in a
# deferred world, so just use it
rpcinterface = xmlrpc.RPCInterface(supervisord)
if action:
if action == 'refresh':
def donothing():
message = 'Page refreshed at %s' % time.ctime()
return message
donothing.delay = 0.05
return donothing
elif action == 'stopall':
callback = rpcinterface.supervisor.stopAllProcesses()
def stopall():
if callback() is NOT_DONE_YET:
return NOT_DONE_YET
else:
return 'All stopped at %s' % time.ctime()
stopall.delay = 0.05
return stopall
elif action == 'restartall':
callback = rpcinterface.system.multicall(
[ {'methodName':'supervisor.stopAllProcesses'},
{'methodName':'supervisor.startAllProcesses'} ] )
def restartall():
result = callback()
if result is NOT_DONE_YET:
return NOT_DONE_YET
return 'All restarted at %s' % time.ctime()
restartall.delay = 0.05
return restartall
elif processname:
if not supervisord.processes.get(processname):
def wrong():
return 'No such process named %s' % processname
wrong.delay = 0.05
return wrong
elif action == 'stop':
callback = rpcinterface.supervisor.stopProcess(processname)
def stopprocess():
result = callback()
if result is NOT_DONE_YET:
return NOT_DONE_YET
return 'Process %s stopped' % processname
stopprocess.delay = 0.05
return stopprocess
elif action == 'restart':
callback = rpcinterface.system.multicall(
[ {'methodName':'supervisor.stopProcess',
'params': [processname]},
{'methodName':'supervisor.startProcess',
'params': [processname]},
]
)
def restartprocess():
result = callback()
if result is NOT_DONE_YET:
return NOT_DONE_YET
return 'Process %s restarted' % processname
restartprocess.delay = 0.05
return restartprocess
elif action == 'start':
try:
callback = rpcinterface.supervisor.startProcess(
processname)
except xmlrpc.RPCError, e:
if e.code == xmlrpc.Faults.SPAWN_ERROR:
def spawnerr():
return 'Process %s spawn error' % processname
spawnerr.delay = 0.05
return spawnerr
def startprocess():
if callback() is NOT_DONE_YET:
return NOT_DONE_YET
return 'Process %s started' % processname
startprocess.delay = 0.05
return startprocess
elif action == 'clearlog':
callback = rpcinterface.supervisor.clearProcessLog(
processname)
def clearlog():
return 'Log for %s cleared' % processname
clearlog.delay = 0.05
return clearlog
raise ValueError(action)
def render(self):
request = self.context.request
response = self.context.response
path, params, query, fragment = request.split_uri()
if query:
while query.startswith('?'):
query = query[1:]
qparams = cgi.parse_qs(query or '')
processname = qparams.get('processname',[None])[0]
action = qparams.get('action', [None])[0]
message = qparams.get('message', [None])[0]
if action:
if not self.callback:
self.callback = self.make_callback(processname, action)
return NOT_DONE_YET
else:
message = self.callback()
if message is NOT_DONE_YET:
return NOT_DONE_YET
if message is not None:
server_url = request.get_server_url()
location = server_url + '?message=%s' % urllib.quote(
message)
response['headers']['Location'] = location
supervisord = self.context.supervisord
rpcinterface = xmlrpc.RPCInterface(supervisord)
processnames = supervisord.processes.keys()
processnames.sort()
data = []
for processname in processnames:
actions = self.actions_for_process(
supervisord.processes[processname])
info = rpcinterface.supervisor.getProcessInfo(processname)
data.append({
'status':info['statename'],
'name':processname,
'actions':actions,
'state':info['state'],
'description':info['description'],
})
root = self.clone()
if message is not None:
statusarea = root.findmeld('statusmessage')
statusarea.attrib['class'] = 'statusmessage'
statusarea.content(message)
if data:
iterator = root.findmeld('tr').repeat(data)
for element, item in iterator:
status_text = element.findmeld('status_text')
status_text.content(item['status'])
status_text.attrib['class'] = self.css_class_for_state(
item['state'])
info_text = element.findmeld('info_text')
info_text.content(item['description'])
anchor = element.findmeld('name_anchor')
processname = item['name']
anchor.attributes(href='tail.html?processname=%s' % processname)
anchor.content(processname)
actions = item['actions']
actionitem_td = element.findmeld('actionitem_td')
for element, actionitem in actionitem_td.repeat(actions):
if actionitem is None:
element.content(' ', structure=True)
else:
anchor = element.findmeld('actionitem_anchor')
anchor.attributes(href=actionitem['href'])
anchor.content(actionitem['name'])
if actionitem['target']:
anchor.attributes(target=actionitem['target'])
else:
table = root.findmeld('statustable')
table.replace('No programs to manage')
return root.write_xhtmlstring()
VIEWS = {
'index.html': {
'template':'ui/status.html',
'view':StatusView
},
'tail.html': {
'template':'ui/tail.html',
'view':TailView,
},
}
class supervisor_ui_handler(default_handler.default_handler):
IDENT = 'Supervisor Web UI HTTP Request Handler'
def __init__(self, filesystem, supervisord):
self.supervisord = supervisord
default_handler.default_handler.__init__(self, filesystem)
def get_view(self, request):
path, params, query, fragment = request.split_uri()
if '%' in path:
path = cgi.unquote(path)
# strip off all leading slashes
while path and path[0] == '/':
path = path[1:]
if not path:
path = 'index.html'
viewdata = VIEWS.get(path)
return viewdata
def handle_request(self, request):
viewdata = self.get_view(request)
if viewdata:
self.do_view_request(viewdata, request)
else:
return default_handler.default_handler.handle_request(self, request)
def do_view_request(self, viewdata, request):
response = {}
response['headers'] = {}
viewclass = viewdata['view']
viewtemplate = viewdata['template']
context = ViewContext(template=viewtemplate,
request=request,
response=response,
supervisord=self.supervisord)
view = viewclass(context)
pushproducer = request.channel.push_with_producer
pushproducer(DeferredWebProducer(request, view))