Переписан процесс отображения хода выполнения задачи.

Отображение полностью используется Methods() из core.
Взаимодейстуется с Receiver объектом.
develop 3.2.0_alpha7
Mike khiretskiy 10 years ago
parent 00ba4fdc15
commit 257fa1da0c

@ -13,6 +13,7 @@
# 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.
from calculate.core.server.replace_class import Display, Methods
from sudsds import WebFault
from sudsds.transport import TransportError
@ -22,7 +23,6 @@ import traceback as tb
import time, logging
import os, sys
import threading, urllib2
from function import analysis, clear, get_entire_frame, get_view_params
from pid_information import client_list_methods
from cert_func import client_post_auth, client_post_request, client_get_cert,\
client_post_cert, get_password_from_daemon, clear_password
@ -33,10 +33,21 @@ import M2Crypto, OpenSSL
from calculate.core.datavars import DataVarsCore
from client_class import HTTPSClientCertTransport
from methods_func import call_method, get_method_argparser, parse, get_view
from function import MessageReceiver, MessageDispatcher, clear, _print, \
get_view_params
from calculate.lib.utils.files import makeDirectory, readLinesFile
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_console3',sys.modules[__name__])
def get_message_receiver(client):
return MessageReceiver(client, MessageDispatcher(Methods()), Display())
def get_entire_message_receiver(client, pid):
return MessageReceiver.from_entire(client, pid,
MessageDispatcher(Methods()), Display())
def client_signal(client):
Vars = DataVarsCore()
Vars.importCore()
@ -235,11 +246,23 @@ def https_server(client, args, unknown_args, url, clVarsCore, wait_thread):
else:
from pid_information import client_list_pid
client_list_pid(client)
return 0
try:
client.frame_period = clVarsCore.Get('core.cl_core_get_frame_period')
except:
client.frame_period = 2
if args.pid_res:
wait_thread.stop()
get_entire_frame(client, args.pid_res)
return 0
mr = get_entire_message_receiver(client, args.pid_res)
if mr:
mr.get_messages()
if not args.keep_result:
client.service.clear_pid_cache(client.sid, args.pid_res)
return 0
else:
return 1
if args.pid_kill:
wait_thread.stop()
@ -265,15 +288,13 @@ def https_server(client, args, unknown_args, url, clVarsCore, wait_thread):
client.service.clear_method_cache(client.sid, args.method)
else:
try:
client.frame_period = clVarsCore.Get('core.cl_core_get_frame_period')
except:
client.frame_period = 2
method_result = call_method(client, args, unknown_args, wait_thread)
mr = get_message_receiver(client)
if method_result:
client.no_progress = args.no_progress
try:
analysis(client, client.sid, method_result)
mr.analysis(method_result)
#analysis(client, client.sid, method_result)
except urllib2.URLError, e:
_print (e)
except KeyboardInterrupt:
@ -290,10 +311,9 @@ def https_server(client, args, unknown_args, url, clVarsCore, wait_thread):
print _("Session not matching your certificate")
elif result == 1:
print _("Failed to terminate the process")
# get_entire_frame(client, pid)
analysis(client, client.sid, method_result)
mr.analysis(method_result)
except Exception, e:
_print (e.message)
_print(e.message)
try:
mess = method_result[0][0]
@ -302,7 +322,8 @@ def https_server(client, args, unknown_args, url, clVarsCore, wait_thread):
return 1
retCode = \
1 if int(client.service.pid_info(client.sid,pid)[0][1]) else 0
client.service.clear_pid_cache(client.sid, pid)
if not args.keep_result:
client.service.clear_pid_cache(client.sid, pid)
client.service.clear_method_cache(client.sid, args.method)
wait_thread.stop()
return retCode

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# Copyright 2012-2013 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2012-2014 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -13,39 +13,24 @@
# 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.
from itertools import cycle
import time, os, sys, re
from fcntl import ioctl
from array import array
import termios
import time, os, sys
import subprocess
from OpenSSL import crypto
import shlex
from calculate.core.server.func import shortTraceback
from calculate.lib.utils.colortext import get_terminal_print
from sudsds import MethodNotFound
from calculate.core.client.function import create_obj
from calculate.core.server.api_types import ArrayReturnedMessage, TableAdapter
from calculate.core.server.cert_cmd import getHwAddr, getIpLocal
from calculate.core.server.replace_class import (printTable, Methods,
print_brief_group)
from calculate.core.server.replace_class import print_brief_group
from calculate.core.client.progressbar import Bar,Percentage,ETA,ProgressBar
from calculate.lib.cl_lang import setLocalTranslate
from calculate.lib.cl_print import color_print
setLocalTranslate('cl_console3',sys.modules[__name__])
from calculate.core.client.function import create_obj
green = '\033[32m * \033[0m'
red = '\033[31m * \033[0m'
from sudsds import MethodNotFound
class _color_print(color_print):
def _printSUCCESS(self, string, offsetL=0, printBR=True):
self.printSUCCESS(string.encode('utf-8'), offsetL, printBR)
setLocalTranslate('cl_console3', sys.modules[__name__])
colorPrint = _color_print()
def _print (*args):
print " ".join(map(lambda x:unicode(x).encode('utf-8'),args))
def _print(*args):
print " ".join(map(lambda x: unicode(x).encode('utf-8'), args))
# get list of certificate and session id
def get_sid (SID_FILE):
@ -68,8 +53,8 @@ def clear ():
#print "delete", filename
try:
os.unlink (filename)
except OSError, e:
_print (e.message)
except OSError as e:
_print(e.message)
except:
print _("Failed to clear the cache! ")
return 1
@ -107,90 +92,29 @@ def print_brief(view, brief_label):
continue
print_brief_group(Group.fields.Field, Group.name)
class switch(object):
def __init__(self, value):
self.value = value
self.fall = False
def __iter__(self):
"""Return the match method once, then stop"""
yield self.match
raise StopIteration
def match(self, *args):
"""Indicate whether or not to enter a case suite"""
if self.fall or not args:
return True
elif self.value in args: # changed for v1.5, see below
self.fall = True
return True
else:
return False
#################API FUNCTION###############################
def show_view(view):
return
print "+====== show view! ======+"
def show_table(table, item):
if item.message:
colorPrint._printSUCCESS(item.message)
head = table.head.string if hasattr (table.head, 'string') else None
data = []
for line in table.body[0]:
if hasattr (line, 'string'):
data.append(line.string)
res = printTable(data, head)
sys.stdout.write(res+"\n")
sys.stdout.flush()
def show_error(item):
if item.message:
for line in item.message.splitlines():
Methods().printERROR(line)
def show_warning(item):
if item.message:
for line in item.message.splitlines():
Methods().printWARNING(line)
def show_group(item):
if item.message:
for line in item.message.splitlines():
Methods().printSUCCESS(line)
def show_result(result):
pass
def startTask(item):
if item.message:
for line in item.message.splitlines():
Methods().printSUCCESS(line)
#colorPrint._printSUCCESS(line)
def endTask(item):
if item.result is None:
result = item.message
else:
result = item.result
methods = Methods()
methods.terminal_print.up(1)('\r')
Methods().displayResult(result)
def beginFrame(item):
pass
def endFrame(item):
pass
def startGroup(item):
if item.message:
Methods().startGroup(item.message)
def endGroup(item):
pass
def _return_revoked_serials(self, crlfile):
try:
serials = []
crltext = open(crlfile, 'r').read()
crl = crypto.load_crl(crypto.FILETYPE_PEM, crltext)
revs = crl.get_revoked()
for revoked in revs:
serials.append(str(revoked.get_serial()))
return serials
except (ImportError, AttributeError):
call = '/usr/bin/openssl crl -text -noout -in %s' % crlfile
call = shlex.split(call)
serials = []
(res,err)=subprocess.Popen(call, stdout=subprocess.PIPE).communicate()
for line in res.split('\n'):
if line.find('Serial Number:') == -1:
continue
(crap, serial) = line.split(':')
serial = serial.strip()
serial = int(serial, 16)
serials.append(serial)
return serials
def _create_obj(client, method):
try:
@ -211,285 +135,207 @@ def get_view_params(client, method, step = None, expert = None, brief = None,
view_params.onlyhelp = onlyhelp
return view_params
def callView(client, item, sid):
return
_print ("\n",item.message)
try:
view_params = get_view_params(client, item.message, brief = True, \
expert = True)
view = client.service[0][item.message] (sid, view_params)
show_view(view)
except:
pass
#################MESSAGE####################################
def analysis(client, sid, s):
""" analysis of the bounced message method """
messages = s[0]
for mess in messages:
if mess.type == 'pid':
try:
pid = int(mess.message)
except:
show_error(_('the server sent PID = ') + pid)
return 1
get_messages(client, sid, pid)
elif mess.type == 'error':
show_error(mess)
elif mess.type == 'warning':
show_warning(mess)
def get_message(client, item, sid, pid):
""" get one message by its type """
for case in switch(item.type):
if case('normal'):
if item.message:
Methods().printSUCCESS(item.message)
return 1
if case('plain'):
if item.message:
Methods().printDefault(item.message)
return 1
if case('pre'):
if item.message:
Methods().printPre(item.message)
return 1
if case('choice'):
message, answers = item.message.split('|')
answers = map(lambda x: (x[0], x[1].strip(')')),
map(lambda x: x.split('('),
answers.split(',')))
answer = Methods().askChoice(message, answers)
client.service.send_message(sid, pid, answer)
return 1
if case('progress'):
if not client.no_progress:
get_Progress(client, sid, pid, item.id)
return 1
if case('error'):
show_error(item)
if item.message == "403 Forbidden":
return 0
return 1
if case('warning'):
show_warning(item)
return 1
if case('table'):
get_Table(client, sid, pid, item)
return 1
if case('group'):
show_group(client, sid, pid, item)
return 1
if case('question'):
send_Message(client, sid, pid, item)
return 1
if case('confirm'):
send_Confirm(client, sid, pid, item)
return 1
if case('password'):
send_Password(client, sid, pid, item)
return 1
if case('startTask'):
startTask(item)
return 1
if case('endTask'):
endTask(item)
return 1
if case('beginFrame'):
beginFrame(item)
return 1
if case('endFrame'):
endFrame(item)
return 0
if case('startGroup'):
startGroup(item)
return 1
if case('endGruop'):
endGroup(item)
return 1
if case('briefParams'):
callView(client, item, sid)
if case(): # default, could also just omit condition or 'if True'
return 1
def get_messages(client, sid, pid):
""" get frame in a separate thread """
#thread_messages = threading.Thread(target=get_Frame,\
#args = (client, sid, pid))
#thread_messages.start()
get_Frame(client, sid, pid)
def get_Frame(client, sid, pid):
""" get all messages, until type is not endFrame (or Error) """
end_frame = 1
spinner = cycle('/-\|')
while end_frame:
current_frame = client.service[0].get_frame(sid, pid, "console")
sys.stdout.write(spinner.next())
sys.stdout.flush()
while current_frame in [None, [], ""]:
sys.stdout.write("\b%s"% spinner.next())
sys.stdout.flush()
time.sleep(float(client.frame_period)/10)
current_frame = client.service[0].get_frame(sid, pid, "console")
sys.stdout.write('\b')
sys.stdout.flush()
for item in current_frame[0]:
end_frame = get_message(client, item, sid, pid)
def get_entire_frame(client, pid):
""" get entire frame, from beginning (if client disconnected) """
sid = get_sid(client.SID_FILE)
list_pid = client.service.list_pid(sid = sid)
if hasattr (list_pid, 'integer'):
if not pid in list_pid.integer:
print \
_('The process does not exist or does not belong to your session')
end_frame = 1
while end_frame:
current_frame = client.service.get_entire_frame(sid, pid)
while current_frame in [None, [], ""]:
time.sleep(1)
current_frame = client.service.get_frame(sid, pid, "console")
for item in current_frame[0]:
end_frame = get_message(client, item, sid, pid)
def get_Progress(client, sid, pid, id):
widgets = ['', '', Bar(), '', Percentage(), ' ', ETA()]
pbar = ProgressBar(widgets=widgets, maxval=100)
pbar.start()
""" get progress for the current job """
returnProgr = client.service.get_progress(sid, pid, id)
temp_progress = -1
last_message = ''
percent = returnProgr.percent
try:
while percent <= 100 and percent >= 0:
if temp_progress != percent:
last_message = print_progressbar(returnProgr, pbar,
last_msg=last_message)
if percent == 100:
return
temp_progress = percent
else:
pbar.update(percent)
time.sleep(1)
returnProgr = client.service.get_progress(sid, pid, id)
percent = returnProgr.percent
if percent < 0:
pbar.update(0)
pbar.finish()
else:
pbar.update(100)
pbar.finish()
finally:
terminal_print = \
get_terminal_print(color_print().defaultPrint)
terminal_print.up(1).clear_line("")
#terminal_print.up(1)("")
def cout_progress(string):
h,w=array('h', ioctl(sys.stderr,termios.TIOCGWINSZ,'\0'*8))[:2]
sys.stdout.write('\r' + (' '*(w)))
sys.stdout.write('\r' + string)
sys.stdout.flush()
def cout(string):
sys.stdout.write(string)
sys.stdout.flush()
def print_progressbar(returnProgr, pbar, last_msg = None, error = False):
if returnProgr.long_message:
if last_msg != returnProgr.long_message:
colorPrint._printSUCCESS('%s\n' %returnProgr.long_message)
pbar.update(returnProgr.percent)
return returnProgr.long_message
elif returnProgr.short_message:
if last_msg != returnProgr.short_message:
colorPrint._printSUCCESS('%s\n' %returnProgr.short_message)
pbar.update(returnProgr.percent)
return returnProgr.short_message
else:
pbar.update(returnProgr.percent)
return last_msg
def print_progress(returnProgr, last_msg = None, error = False):
if error:
cout_progress (red + '\n'+_("Task error by %s") \
%str(0 - returnProgr.percent).rjust(5) + '%\n')
return ''
elif returnProgr.long_message:
if last_msg == returnProgr.long_message:
cout_progress('%s%%' %str(returnProgr.percent).rjust(5))
else:
if not last_msg:
cout_progress('')
else:
cout_progress('OK'.rjust(6) + '\n')
cout_progress(green + '%s %s%%' %(returnProgr.long_message, \
str(returnProgr.percent).rjust(5)))
return returnProgr.long_message
elif returnProgr.short_message:
if last_msg == returnProgr.short_message:
cout_progress('%s%%' %str(returnProgr.percent).rjust(5))
class MessageReceiver(object):
"""
Объект организует цикл получения сообщений от WsdlServer и передает их на
обработку MessageDispatcher
"""
class States:
Messages = 0
Progress = 1
Finish = 2
def __init__(self, client, message_dispatcher=None, display=None):
"""
@param display: Display
@param message_dispatcher: MessageDispatcher
"""
self.client = client
self.sid = client.sid
self.message_dispatcher = message_dispatcher
self.message_dispatcher.parent = self
self.display = display
self.state = self.States.Messages
self.pid = 0
self.entire = False
@classmethod
def from_entire(cls, client, pid, message_dispatcher=None, display=None):
sid = get_sid(client.SID_FILE)
list_pid = client.service.list_pid(sid=sid)
if hasattr(list_pid, 'integer'):
if not pid in list_pid.integer:
display.print_error(
_("The process does not exist or does not belong to "
"your session"))
return None
obj = cls(client, message_dispatcher, display)
obj.sid = sid
obj.pid = pid
obj.entire = True
return obj
def analysis(self, method_result):
""" analysis of the bounced message method """
messages = ArrayReturnedMessage.from_detect(method_result)
for message in messages:
if message.type == 'pid':
try:
self.pid = int(message.message)
except (ValueError, AttributeError):
self.display.print_error(
_('the server sent PID = ') + str(message))
return 1
try:
self.get_messages()
except Exception as e:
import traceback
traceback.print_exc()
elif message.type == 'error':
self.display.print_error(message.message)
elif message.type == 'warning':
self.display.print_warning(message.message)
def get_client_frame(self):
if self.entire:
self.entire = False
return self.client.service[0].get_entire_frame(self.sid, self.pid,
"console")
else:
if not last_msg:
cout_progress('')
else:
cout_progress('OK'.rjust(6) + '\n')
cout_progress(green + '%s %s%%' %(returnProgr.short_message, \
str(returnProgr.percent).rjust(5)))
return returnProgr.short_message
else:
# print '%s' %str(returnProgr.percent).rjust(5) + '%'
cout_progress ('%s' %str(returnProgr.percent).rjust(5) + '%')
return ''
def get_Table(client, sid, pid, item):
table = client.service.get_table(sid, pid, item.id)
show_table(table, item)
def send_Confirm(client,sid,pid,item):
ask = Methods().askConfirm(item.message, item.default or "")
client.service.send_message(sid, pid, ask)
def send_Message(client, sid, pid, item):
""" send answer to the question """
print
answer = raw_input (item.message)
client.service.send_message(sid, pid, answer)
# show_result(result)
def send_Password(client, sid, pid, item):
""" send password """
from getpass import getpass
password = getpass(prompt=item.message)
result = client.service.send_message(sid, pid, password)
show_result(result)
return self.client.service[0].get_frame(self.sid, self.pid,
"console")
def get_messages(self):
""" get all messages, until type is not endFrame (or Error) """
self.state = self.States.Messages
while self.state != self.States.Finish:
if self.state == self.States.Messages:
current_frame = self.get_client_frame()
while current_frame in [None, [], ""]:
time.sleep(float(self.client.frame_period)/10)
current_frame = self.get_client_frame()
for item in current_frame[0]:
self.message_dispatcher.dispatch_message(item)
def get_client_progress(self, id):
return self.client.service.get_progress(self.sid, self.pid, id).percent
def get_progress(self, id):
percent = self.get_client_progress(id)
yield percent
while 0 <= percent < 100:
time.sleep(0.2)
temp_percent = self.get_client_progress(id)
if temp_percent != percent:
percent = temp_percent
yield percent
if percent < 0:
yield 0
elif percent > 100:
yield 100
def get_table(self, id):
return self.client.service.get_table(self.sid, self.pid, id)
def send_message(self, message):
self.client.service.send_message(self.sid, self.pid, message)
class MessageDispatcher(object):
"""
Объект разбирает полученное сообщение Message через функцию dispatch_message
В дальнейшем взаимодействует с parent через методы get_progress, get_table,
send_message, поле State
"""
def __init__(self, methods=None):
"""
@param methods: Common
"""
self.methods = methods
self.parent = None
self.dispatchers = {'endFrame': self.end_frame,
'progress': self.progress,
'startTask': self.start_task,
'endTask': self.end_task,
'startGroup': self.start_group,
'endGroup': self.end_group,
'normal': self.print_success,
'error': self.print_error,
'warning': self.print_warning,
'pre': self.print_pre,
'plain': self.print_default,
'table': self.print_table,
'choice': self.ask_choice,
'confirm': self.ask_confirm,
'question': self.ask_question,
}
def default_action(self, message):
pass
def _return_revoked_serials(self, crlfile):
try:
serials = []
crltext = open(crlfile, 'r').read()
crl = crypto.load_crl(crypto.FILETYPE_PEM, crltext)
revs = crl.get_revoked()
for revoked in revs:
serials.append(str(revoked.get_serial()))
return serials
except (ImportError, AttributeError):
call = '/usr/bin/openssl crl -text -noout -in %s' % crlfile
call = shlex.split(call)
serials = []
(res,err)=subprocess.Popen(call, stdout=subprocess.PIPE).communicate()
for line in res.split('\n'):
if line.find('Serial Number:') == -1:
continue
(crap, serial) = line.split(':')
serial = serial.strip()
serial = int(serial, 16)
serials.append(serial)
return serials
def dispatch_message(self, message):
self.dispatchers.get(message.type, self.default_action)(message)
def end_frame(self, message):
self.parent.state = self.parent.States.Finish
def progress(self, message):
self.methods.addProgress(message.message)
for perc in self.parent.get_progress(message.id):
self.methods.setProgress(perc)
def start_task(self, message):
self.methods.startTask(message.message)
def end_task(self, message):
self.methods.endTask(message.message)
def start_group(self, message):
self.methods.startGroup(message.message)
def end_group(self, message):
self.methods.endGroup()
def print_success(self, message):
self.methods.printSUCCESS(message.message)
def print_error(self, message):
self.methods.printERROR(message.message)
if "403 Forbidden" in message.message:
self.parent.state = self.parent.States.Finish
def print_warning(self, message):
self.methods.printWARNING(message.message)
def print_pre(self, message):
self.methods.printPre(message.message)
def print_default(self, message):
self.methods.printDefault(message.message)
def print_table(self, message):
table = TableAdapter.from_detect(self.parent.get_table(message.id))
self.methods.printTable(message.message, table.head, table.body)
def ask_choice(self, message):
message, answers = message.message.split('|')
answers = map(lambda x: (x[0], x[1].strip(')')),
map(lambda x: x.split('('),
answers.split(',')))
answer = self.methods.askChoice(message, answers)
self.parent.send_message(answer)
def ask_confirm(self, message):
answer = self.methods.askConfirm(message.message, message.default or "")
self.parent.send_message(answer)
def ask_question(self, message):
answer = self.methods.askQuestion(message.message)
self.parent.send_message(answer)
def ask_password(self, message):
answer = self.methods.askPassword(message.message, message.id == 2)
self.parent.send_message(answer)

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# Copyright 2012-2013 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2012-2014 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -17,10 +17,10 @@
import argparse, sys
from calculate.core.server.api_types import ViewInfoAdapter
from calculate.core.server.replace_class import Methods
from function import _create_obj, get_view_params, print_brief, _print, \
colorPrint
from function import _create_obj, get_view_params, print_brief, _print
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_console3',sys.modules[__name__])
setLocalTranslate('cl_console3', sys.modules[__name__])
import urllib2
from calculate.core.server.methods_func import get_method_argparser, \
@ -65,6 +65,9 @@ def parse():
parser.add_argument(
'--pid-result', type=int, metavar = 'PID',
dest='pid_res', help=_("view the result of the process"))
parser.add_argument(
'--keep-result', action='store_true', default=False,
dest='keep_result', help=_("keep cache of process result"))
parser.add_argument(
'--pid-kill', type=int, metavar = 'PID',
dest='pid_kill', help=_("kill the selected process"))
@ -108,8 +111,8 @@ def get_view(client, method, sid, view_params):
def call_method(client, args, unknown_args, wait_thread):
method = args.method
stdin_passwd = args.stdin_passwd
view_params = get_view_params(client, method + '_view', step = None, \
expert = True)
view_params = get_view_params(client, method + '_view', step=None, \
expert=True)
view = get_view(client, method, client.sid, view_params)
method_parser = get_method_argparser(view, args)
@ -167,7 +170,7 @@ def call_method(client, args, unknown_args, wait_thread):
except KeyboardInterrupt:
ask = "no"
if ask.lower() in ['n', 'no']:
colorPrint.printERROR(_('Manually interrupted'))
Methods().printERROR(_('Manually interrupted'))
return None
param_object['CheckOnly'] = False

Loading…
Cancel
Save